les pandas écrasent les valeurs dans plusieurs colonnes à la fois en fonction de l'état des valeurs dans une colonne

11

J'ai un tel 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']})

Je veux obtenir la longueur de la liste après la division sur ":" dans col1, puis je veux écraser les valeurs si longueur> 2 OU ne pas écraser les valeurs si longueur <= 2.

Idéalement, en une seule ligne aussi vite que possible.

Actuellement, j'essaye mais il retourne ValueError.

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

EDIT: condition sur col1. EDIT2: merci pour toutes les bonnes réponses fournies rapidement. incroyable! EDIT3: chronométrage sur 10 ^ 6 lignes:

@ansev 3.2657s

@jezrael 0.8922s

@ anky_91 1.9511s

dkrynicki
la source
La condition est-elle sur col2ou col1?
anishtain4
Je m'excuse pour l'erreur. C'est col1.
dkrynicki

Réponses:

8

Utilisez Series.str.count, ajoutez 1, comparez par Series.gtet attribuez la liste aux colonnes filtrées de la liste:

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
jezrael
la source
2
C'est la meilleure réponse car elle ne stocke pas de fractionnement temporaire, mais pourquoi ne pas utiliser gt(1)au lieu d'ajouter 1 et gt(2)?
anishtain4
@ anishtain4 - yop, d'accord
jezrael
10

Vous avez besoin series.str.len()après la division pour déterminer la longueur de la liste, puis vous pouvez comparer et utiliser .loc[], affecter la liste partout où la condition correspond:

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
anky
la source
5

Une autre approche est Series.str.splitavec expand = Trueet DataFrame.countavec 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
ansev
la source