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.