i panda sovrascrivono i valori in più colonne contemporaneamente in base alla condizione dei valori in una colonna


11

Ho un tale DataFrame:

df = pd.DataFrame(data={
    'col0': [11, 22,1, 5]
    'col1': ['aa:a:aaa', 'a:a', 'a', 'a:aa:a:aaa'],
    'col2': ["foo", "foo", "foobar", "bar"],
    'col3': [True, False, True, False],
    'col4': ['elo', 'foo', 'bar', 'dupa']})

Voglio ottenere la lunghezza della lista dopo aver diviso ":" in col1, quindi voglio sovrascrivere i valori se lunghezza> 2 O non sovrascrivere i valori se lunghezza <= 2.

Idealmente, in una riga il più velocemente possibile.

Attualmente, ci provo ma restituisce ValueError.

df[['col1', 'col2', 'col3']] = df.loc[df['col1'].str.split(":").apply(len) > 2], ("", "", False), df[['col1', 'col2', 'col3']])

EDIT: condizione su col1. EDIT2: grazie per tutte le grandiose risposte fornite rapidamente. sorprendente! EDIT3: timing su 10 ^ 6 righe:

@ansev 3.2657s

@jezrael 0.8922s

@ anky_91 1.9511s


La condizione è attiva col2o col1?
anishtain4

Mi scuso per l'errore. È col1.
dkrynicki,

Risposte:


8

Usa Series.str.count, aggiungi 1, confronta per Series.gte assegna l'elenco alle colonne filtrate nell'elenco:

df.loc[df['col1'].str.count(":").add(1).gt(2), ['col1','col2','col3']] = ["", "", False]
print (df)
   col0 col1    col2   col3  col4
0    11               False   elo
1    22  a:a     foo  False   foo
2     1    a  foobar   True   bar
3     5               False  dupa

2
Questa è la risposta migliore in quanto non memorizza una divisione temporanea, ma perché non utilizzare gt(1)invece di aggiungere 1 e gt(2)?
anishtain4

@ anishtain4 - yop, d'accordo
jezrael

10

È necessario series.str.len()dopo aver diviso per determinare la lunghezza dell'elenco, quindi è possibile confrontare e utilizzare .loc[], assegnare l'elenco ovunque la condizione corrisponda:

df.loc[df['col1'].str.split(":").str.len()>2,['col1','col2','col3']]=["", "", False]
print(df)

   col0 col1    col2   col3  col4
0    11               False   elo
1    22  a:a     foo  False   foo
2     1    a  foobar   True   bar
3     5               False  dupa

5

Un altro approccio è Series.str.splitcon expand = Truee DataFrame.countcon axis=1.

df.loc[df['col1'].str.split(":",expand = True).count(axis=1).gt(2),['col1','col2','col3']]=["", "", False]
print(df)
   col0 col1    col2   col3  col4
0    11               False   elo
1    22  a:a     foo  False   foo
2     1    a  foobar   True   bar
3     5               False  dupa
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.