i dtypes mettono le cose a posto quando si sposta sull'asse uno (colonne)


9

Considera il frame di dati df

df = pd.DataFrame(dict(A=[1, 2], B=['X', 'Y']))

df

   A  B
0  1  X
1  2  Y

Se passo avanti axis=0(impostazione predefinita)

df.shift()

     A    B
0  NaN  NaN
1  1.0    X

Spinge tutte le file verso il basso di una riga come previsto.

Ma quando passo avanti axis=1

df.shift(axis=1)

    A    B
0 NaN  NaN
1 NaN  NaN

Tutto è nullo quando mi aspettavo

     A  B
0  NaN  1
1  NaN  2

Capisco perché è successo. Infatti axis=0, Pandas opera colonna per colonna dove ogni colonna è una singola dtypee quando si sposta, esiste un protocollo chiaro su come gestire il NaNvalore introdotto all'inizio o alla fine. Ma quando ci spostiamo axis=1introduciamo una potenziale ambiguità dtypeda una colonna all'altra. In questo caso, sto cercando di forzare int64una objectcolonna e Panda decide di annullare i valori.

Questo diventa più problematico quando lo dtypessono int64efloat64

df = pd.DataFrame(dict(A=[1, 2], B=[1., 2.]))

df

   A    B
0  1  1.0
1  2  2.0

E succede la stessa cosa

df.shift(axis=1)

    A   B
0 NaN NaN
1 NaN NaN

La mia domanda

Quali sono le buone opzioni per la creazione di un frame di dati che viene spostato lungo il axis=1quale il risultato ha spostato valori e tipi?

Per il caso int64/ float64il risultato sarebbe simile a:

df_shifted

     A  B
0  NaN  1
1  NaN  2

e

df_shifted.dtypes

A    object
B     int64
dtype: object

Un esempio più completo

df = pd.DataFrame(dict(A=[1, 2], B=[1., 2.], C=['X', 'Y'], D=[4., 5.], E=[4, 5]))

df

   A    B  C    D  E
0  1  1.0  X  4.0  4
1  2  2.0  Y  5.0  5

Dovrebbe apparire così

df_shifted

     A  B    C  D    E
0  NaN  1  1.0  X  4.0
1  NaN  2  2.0  Y  5.0

df_shifted.dtypes

A     object
B      int64
C    float64
D     object
E    float64
dtype: object

A me sembra un bug, cosa succede se crei i tipi di tutte le colonne object?
— EdChum,

Funziona. Ho già un paio di soluzioni. Sto solo prendendo in giro la comunità per alcune idee.
— piRSquared

Presenterei questo come un problema, dovrebbero almeno offrire un'opzione per la promozione del tipo a un tipo misto comeobject
— EdChum,

Lo farò ora.
— piRSquared

1
@ EdChum-ReinstateMonica Aspetta un minuto! Lo spostamento avviene sopra blocks>. <Usa questo invece e vedidf = pd.DataFrame(dict(A=[1, 2], B=[3., 4.], C=['X', 'Y'], D=[5., 6.], E=[7, 8], F=['W', 'Z']))
— piRSquared il

Risposte:


7

Si scopre che Panda si sta spostando su blocchi di simili dtypes

Definisci dfcome

df = pd.DataFrame(dict(
    A=[1, 2], B=[3., 4.], C=['X', 'Y'],
    D=[5., 6.], E=[7, 8], F=['W', 'Z']
))

df

#  i    f  o    f  i  o
#  n    l  b    l  n  b
#  t    t  j    t  t  j
#
   A    B  C    D  E  F
0  1  3.0  X  5.0  7  W
1  2  4.0  Y  6.0  8  Z

Sposterà gli interi alla colonna intera successiva, i float alla colonna float successiva e gli oggetti alla colonna successiva dell'oggetto

df.shift(axis=1)

    A   B    C    D    E  F
0 NaN NaN  NaN  3.0  1.0  X
1 NaN NaN  NaN  4.0  2.0  Y

Non so se sia una buona idea, ma è quello che sta succedendo.


approcci

astype(object) primo

dtypes = df.dtypes.shift(fill_value=object)
df_shifted = df.astype(object).shift(1, axis=1).astype(dtypes)

df_shifted

     A  B    C  D    E  F
0  NaN  1  3.0  X  5.0  7
1  NaN  2  4.0  Y  6.0  8

transpose

Ce la farà object

dtypes = df.dtypes.shift(fill_value=object)
df_shifted = df.T.shift().T.astype(dtypes)

df_shifted

     A  B    C  D    E  F
0  NaN  1  3.0  X  5.0  7
1  NaN  2  4.0  Y  6.0  8

itertuples

pd.DataFrame([(np.nan, *t[1:-1]) for t in df.itertuples()], columns=[*df])

     A  B    C  D    E  F
0  NaN  1  3.0  X  5.0  7
1  NaN  2  4.0  Y  6.0  8

Anche se probabilmente lo farei

pd.DataFrame([
    (np.nan, *t[:-1]) for t in
    df.itertuples(index=False, name=None)
], columns=[*df])

4
Questo è sicuramente un bug per me, questo invalida l'intero punto di avere colonne con chiave e di spostarsi di N posizioni per quanto riguarda le colonne
— EdChum

1
Pubblicherò un problema dopo il mio incontro.
— piRSquared

Se è tutto strdytpes allora funziona correttamente, se fai lo stesso su questo df df = pd.DataFrame(dict(C=['X', 'Y'], D=[5., 6.], E=[7, 8], F=['W', 'Z']))sposta la 'XY'colonna fino alla 'F'colonna, questo è sicuramente sbagliato per me, la mia versione di Panda è 0.24.2, dovrebbe fare dtypepromozione e non spostare le colonne in tale un modo
— EdChum


1

Ho provato ad usare un numpymetodo. Il metodo funziona fintanto che conservi i tuoi dati in una matrice numpy:

def shift_df(data, n):
    shifted = np.roll(data, n)
    shifted[:, :n] = np.NaN

    return shifted

shifted(df, 1)

array([[nan, 1, 1.0, 'X', 4.0],
       [nan, 2, 2.0, 'Y', 5.0]], dtype=object)

Ma quando chiami il DataFramecostruttore, tutte le colonne vengono convertite in objectsebbene i valori nella matrice siano float, int, object:

def shift_df(data, n):
    shifted = np.roll(data, n)
    shifted[:, :n] = np.NaN
    shifted = pd.DataFrame(shifted)

    return shifted

print(shift_df(df, 1),'\n')
print(shift_df(df, 1).dtypes)

     0  1  2  3  4
0  NaN  1  1  X  4
1  NaN  2  2  Y  5 

0    object
1    object
2    object
3    object
4    object
dtype: object
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.