Zaktualizuj wartości wierszy, w przypadku których spełniony jest określony warunek w pandach

98

Powiedzmy, że mam następującą ramkę danych:

stół

Jaki jest najbardziej efektywny sposób aktualizowania wartości kolumn feat i another_feat, gdzie strumień ma numer 2 ?

Czy to jest to?

for index, row in df.iterrows():
    if df1.loc[index,'stream'] == 2:
       # do something

AKTUALIZACJA: Co zrobić, jeśli mam więcej niż 100 kolumn? Nie chcę jawnie nazywać kolumn, które chcę zaktualizować. Chcę podzielić wartość każdej kolumny przez 2 (z wyjątkiem kolumny strumienia).

Aby było jasne, jaki jest mój cel:

Dzielenie wszystkich wartości przez 2 ze wszystkich wierszy, które mają strumień 2, ale bez zmiany kolumny strumienia

Stanko
źródło

Odpowiedzi:

204

Myślę, że możesz użyć, locjeśli potrzebujesz zaktualizować dwie kolumny do tej samej wartości:

df1.loc[df1['stream'] == 2, ['feat','another_feat']] = 'aaaa'
print df1
   stream        feat another_feat
a       1  some_value   some_value
b       2        aaaa         aaaa
c       2        aaaa         aaaa
d       3  some_value   some_value

Jeśli potrzebujesz aktualizacji oddzielnie, użyj jednej opcji:

df1.loc[df1['stream'] == 2, 'feat'] = 10
print df1
   stream        feat another_feat
a       1  some_value   some_value
b       2          10   some_value
c       2          10   some_value
d       3  some_value   some_value

Inną popularną opcją jest użycie numpy.where:

df1['feat'] = np.where(df1['stream'] == 2, 10,20)
print df1
   stream  feat another_feat
a       1    20   some_value
b       2    10   some_value
c       2    10   some_value
d       3    20   some_value

EDYCJA: Jeśli chcesz podzielić wszystkie kolumny bez streamwarunku True, użyj:

print df1
   stream  feat  another_feat
a       1     4             5
b       2     4             5
c       2     2             9
d       3     1             7

#filter columns all without stream
cols = [col for col in df1.columns if col != 'stream']
print cols
['feat', 'another_feat']

df1.loc[df1['stream'] == 2, cols ] = df1 / 2
print df1
   stream  feat  another_feat
a       1   4.0           5.0
b       2   2.0           2.5
c       2   1.0           4.5
d       3   1.0           7.0
jezrael
źródło
Zaktualizowałem pytanie, mam ponad 100 kolumn, jak mogę to zrobić?
Stanko
1
@Stanko - myślę, że to inne pytanie - musisz 100jakoś wybrać te kolumny. np. jeśli potrzebujesz 100pierwszych kolumn, użyj, df.columns[:100]a następnie przejdź do loc.
jezrael
Niekoniecznie chcę pierwszych 100 kolumn, po prostu chcę podzielić wszystkie wartości kolumn (z wyjątkiem kolumny strumienia) przez 2, gdzie strumień to np. 2
Stanko
więc różnica między loc i np. gdzie jest to, że loc zmienia wiersze, które spełniają tylko warunek, ale np.where ma instrukcję if i else, dlatego zmieni wszystkie wiersze?
Ambleu
1
@Ambleu - dokładnie.
jezrael
3

Możesz zrobić to samo za pomocą .ix, na przykład:

In [1]: df = pd.DataFrame(np.random.randn(5,4), columns=list('abcd'))

In [2]: df
Out[2]: 
          a         b         c         d
0 -0.323772  0.839542  0.173414 -1.341793
1 -1.001287  0.676910  0.465536  0.229544
2  0.963484 -0.905302 -0.435821  1.934512
3  0.266113 -0.034305 -0.110272 -0.720599
4 -0.522134 -0.913792  1.862832  0.314315

In [3]: df.ix[df.a>0, ['b','c']] = 0

In [4]: df
Out[4]: 
          a         b         c         d
0 -0.323772  0.839542  0.173414 -1.341793
1 -1.001287  0.676910  0.465536  0.229544
2  0.963484  0.000000  0.000000  1.934512
3  0.266113  0.000000  0.000000 -0.720599
4 -0.522134 -0.913792  1.862832  0.314315

EDYTOWAĆ

Po dodatkowych informacjach poniższe zwrócą wszystkie kolumny - w przypadku gdy spełniony jest jakiś warunek - z wartościami zmniejszonymi o połowę:

>> condition = df.a > 0
>> df[condition][[i for i in df.columns.values if i not in ['a']]].apply(lambda x: x/2)

Mam nadzieję, że to pomoże!

Thanos
źródło
Jest to możliwe, jeśli nie mam wielu kolumn, powinienem powiedzieć, że mam więcej niż 100 kolumn.
Stanko
Przetestowałem twoją ostatnią edycję, condition = (df.a == -1.001287)spodziewając się, że wartości zostaną podzielone z wiersza, w którym a == -1.001287otrzymałem pustą ramkę danych.
Stanko
Tak, to dlatego, że jest to tylko wyświetlacz, a nie rzeczywista wartość, uzyskać rzeczywistą wartość takiego: df.iloc[1,0]. Albo jeszcze lepiej ustaw wartość samodzielnie i spróbuj ponownie:df.iloc[1,0] = 1.2345; condition = df.a == 1.2345
Thanos
Nie śledzę, dlaczego dokładnie condition = (df.a == -1.001287)nie działa?
Stanko
8
ixjest teraz przestarzała.
dbliss