Панды перезаписывают значения в нескольких столбцах одновременно, основываясь на условии значений в одном столбце

11

У меня есть такой 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']})

Я хочу получить длину списка после разделения на ":" в столбце col1, затем я хочу перезаписать значения, если длина> 2 ИЛИ не перезаписать значения, если длина <= 2.

В идеале в одну строчку максимально быстро.

В настоящее время я пытаюсь, но он возвращает ValueError.

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

РЕДАКТИРОВАТЬ: состояние на col1. EDIT2: спасибо за все великолепные и быстро предоставленные ответы. удивительно! РЕДАКТИРОВАТЬ3: время на 10 ^ 6 строк:

@ansev 3.2657s

@jezrael 0.8922s

@ anky_91 1.9511s

dkrynicki
источник
Состояние на col2или col1?
anishtain4
Я прошу прощения за ошибку. Это col1.
dkrynicki

Ответы:

8

Используйте Series.str.count, добавляйте 1, сравнивайте Series.gtи назначайте список отфильтрованным столбцам в списке:

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
источник
2
Это лучший ответ, так как он не хранит временное разделение, но почему бы не использовать gt(1)вместо добавления 1 и gt(2)?
anishtain4
@ anishtain4 - да, согласен
Джезраэль
10

Вам нужно series.str.len()после разделения определить длину списка, затем вы можете сравнить и, используя .loc[], назначить список там, где соответствует условие:

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

Другой подход Series.str.splitс expand = Trueи DataFrame.countс 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
источник