Modyfikowanie podzbioru wierszy w ramce danych pandy


143

Załóżmy, że mam pandę DataFrame z dwiema kolumnami, A i B. Chciałbym zmodyfikować tę ramkę DataFrame (lub utworzyć kopię), aby B zawsze miało wartość NaN, gdy A wynosi 0. Jak mogę to osiągnąć?

Wypróbowałem następujące

df['A'==0]['B'] = np.nan

i

df['A'==0]['B'].values.fill(np.nan)

bezskutecznie.


Jeśli szukasz bardzo szybkiego rozwiązania, użyj NumPy, wherejak widać na poniższym rozwiązaniu
— Ted Petrou

Odpowiedzi:


243

Użyj .locdo indeksowania na podstawie etykiet:

df.loc[df.A==0, 'B'] = np.nan

df.A==0Ekspresji tworzy logiczną serii, które indeksów wierszy, 'B'wybiera kolumny. Możesz również użyć tego do przekształcenia podzbioru kolumny, np .:

df.loc[df.A==0, 'B'] = df.loc[df.A==0, 'B'] / 2

Nie wiem wystarczająco dużo o elementach wewnętrznych pand, aby dokładnie wiedzieć, dlaczego to działa, ale podstawowym problemem jest to, że czasami indeksowanie do DataFrame zwraca kopię wyniku, a czasami zwraca widok oryginalnego obiektu. Zgodnie z dokumentacją tutaj zachowanie to zależy od podstawowego zachowania numpy. Zauważyłem, że dostęp do wszystkiego w jednej operacji (zamiast [jednej] [dwóch]) jest bardziej prawdopodobny dla ustawienia.


Druga część to miła odpowiedź na pytanie, które nawet nie zostało zadane ;-) Zastanawiam się, czy to nadal jest kanoniczna odpowiedź pandy, w szczególności b / c to oczywiste naruszenie DRY, chociaż zakładam, że jest w fakt konieczny do naruszenia DRY, biorąc pod uwagę ograniczenia wewnętrzne pand? (Mogę zadać dokładnie tego rodzaju pytanie, bardziej szczegółowo, ale chciałem sprawdzić, czy masz szybką odpowiedź, zanim to zrobię)
— JohnE

Jak podzielić Dataframe, która nie ma nazw kolumn, jak podzielić df tylko według indeksu? df.loc [df [0] == 0] nie działa ... Jaka jest alternatywa? Dziękuję
— amipro

89

Oto dokumentacja pandas dotycząca zaawansowanego indeksowania:

Sekcja wyjaśni dokładnie, czego potrzebujesz! Okazuje się, że df.loc(ponieważ .ix został przestarzały - jak wielu wskazało poniżej) może być użyty do fajnego krojenia / kostkowania ramki danych. I. Może być również używany do ustawiania rzeczy.

df.loc[selection criteria, columns I want] = value

Więc odpowiedź Brena brzmi: „znajdź mi wszystkie miejsca df.A == 0, wybierz kolumnę Bi ustaw ją na np.nan”


2
Uczyniłeś mój dzień. Jasne wyjaśnienie.
— TwinPenguins

1
Tak, jakoś loc[selection criteria, columns I want]doskonale trzyma się twojego umysłu ...
— EmE,

29

Począwszy od pand w wersji 0.20 ix jest przestarzały . Właściwym sposobem jest użycie df.loc

oto działający przykład

>>> import pandas as pd 
>>> import numpy as np 
>>> df = pd.DataFrame({"A":[0,1,0], "B":[2,0,5]}, columns=list('AB'))
>>> df.loc[df.A == 0, 'B'] = np.nan
>>> df
   A   B
0  0 NaN
1  1   0
2  0 NaN
>>> 

Wyjaśnienie:

Jak wyjaśniono w dokumencie tutaj , .loc jest oparty głównie etykieta, ale może być również używany z logicznej tablicy .

Tak więc to, co robimy powyżej, to stosowanie df.loc[row_index, column_index]przez:

  • Wykorzystując fakt, że locmoże przyjąć tablicę logiczną jako maskę, która mówi pandom, w którym podzbiorze wierszy chcemy zmienićrow_index
  • Wykorzystanie tego faktu locjest również oparte na etykiecie, aby wybrać kolumnę za pomocą etykiety 'B'wcolumn_index

Możemy użyć operacji logicznej, warunkowej lub dowolnej operacji, która zwraca serię wartości logicznych, aby skonstruować tablicę wartości logicznych. W powyższym przykładzie chcemy, rowsaby zawierała a 0, w tym celu możemy użyć df.A == 0, jak widać w przykładzie poniżej, zwraca to serię wartości logicznych.

>>> df = pd.DataFrame({"A":[0,1,0], "B":[2,0,5]}, columns=list('AB'))
>>> df 
   A  B
0  0  2
1  1  0
2  0  5
>>> df.A == 0 
0     True
1    False
2     True
Name: A, dtype: bool
>>> 

Następnie używamy powyższej tablicy wartości logicznych, aby wybrać i zmodyfikować niezbędne wiersze:

>>> df.loc[df.A == 0, 'B'] = np.nan
>>> df
   A   B
0  0 NaN
1  1   0
2  0 NaN

Aby uzyskać więcej informacji, zapoznaj się z zaawansowaną dokumentacją dotyczącą indeksowania tutaj .


11

Aby uzyskać ogromny wzrost prędkości, użyj funkcji Where NumPy.

Ustawiać

Utwórz dwukolumnową ramkę DataFrame ze 100 000 wierszy z kilkoma zerami.

df = pd.DataFrame(np.random.randint(0,3, (100000,2)), columns=list('ab'))

Szybkie rozwiązanie dzięki numpy.where

df['b'] = np.where(df.a.values == 0, np.nan, df.b.values)

Czasy

%timeit df['b'] = np.where(df.a.values == 0, np.nan, df.b.values)
685 µs ± 6.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit df.loc[df['a'] == 0, 'b'] = np.nan
3.11 ms ± 17.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Numpy wherejest około 4x szybszy


Byłem tego ciekawy, więc przetestowałem to sam i różnica była jeszcze większa przy innych parametrach. Numpy był prawie 10 razy szybszy w zamianie zera na liczbę całkowitą zamiast np.nan. Zastanawiam się, co zajmuje dodatkowy czas.
— Alexander,

Czy konieczne jest użycie .valuesw np.where(df.a.values == 0, np.nan, df.b.values)? Wygląda na to, że np.where(df.a == 0, np.nan, df.b)też działa?
— hsl

4

Aby zamienić kolumny wielokrotności, przekonwertuj je na tablicę numpy używając .values:

df.loc[df.A==0, ['B', 'C']] = df.loc[df.A==0, ['B', 'C']].values / 2
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.