2013-01-07 18 views
12

Podsumowanie: To nie działa:Zrozumienie pandy dataframe indeksowanie

df[df.key==1]['D'] = 1 

ale to robi:

df.D[df.key==1] = 1 

Dlaczego?

Rozmnażanie:

In [1]: import pandas as pd 

In [2]: from numpy.random import randn 

In [4]: df = pd.DataFrame(randn(6,3),columns=list('ABC')) 

In [5]: df 
Out[5]: 
      A   B   C 
0 1.438161 -0.210454 -1.983704 
1 -0.283780 -0.371773 0.017580 
2 0.552564 -0.610548 0.257276 
3 1.931332 0.649179 -1.349062 
4 1.656010 -1.373263 1.333079 
5 0.944862 -0.657849 1.526811 

In [6]: df['D']=0.0 

In [7]: df['key']=3*[1]+3*[2] 

In [8]: df 
Out[8]: 
      A   B   C D key 
0 1.438161 -0.210454 -1.983704 0 1 
1 -0.283780 -0.371773 0.017580 0 1 
2 0.552564 -0.610548 0.257276 0 1 
3 1.931332 0.649179 -1.349062 0 2 
4 1.656010 -1.373263 1.333079 0 2 
5 0.944862 -0.657849 1.526811 0 2 

To nie działa:

In [9]: df[df.key==1]['D'] = 1 

In [10]: df 
Out[10]: 
      A   B   C D key 
0 1.438161 -0.210454 -1.983704 0 1 
1 -0.283780 -0.371773 0.017580 0 1 
2 0.552564 -0.610548 0.257276 0 1 
3 1.931332 0.649179 -1.349062 0 2 
4 1.656010 -1.373263 1.333079 0 2 
5 0.944862 -0.657849 1.526811 0 2 

ale to robi:

In [11]: df.D[df.key==1] = 3.4 

In [12]: df 
Out[12]: 
      A   B   C D key 
0 1.438161 -0.210454 -1.983704 3.4 1 
1 -0.283780 -0.371773 0.017580 3.4 1 
2 0.552564 -0.610548 0.257276 3.4 1 
3 1.931332 0.649179 -1.349062 0.0 2 
4 1.656010 -1.373263 1.333079 0.0 2 
5 0.944862 -0.657849 1.526811 0.0 2 

Link to notebook

Moje pytanie brzmi: Dlaczego tylko 2 sposób pracy? Nie widzę różnicy w logice selekcji/indeksowania?

wersja to 0.10.0

Edit: Nie powinno to być zrobione tak dłużej. Od 0.11 jest .loc, zobacz tutaj: http://pandas.pydata.org/pandas-docs/stable/indexing.html

+0

Jak powiedziałem w odpowiedziach to wydaje się być odrętwiałym problemem: popatrz na [to pytanie] (http://stackoverflow.com/q/9470604/1301710) dla podobnego problemu. Nie jestem pewien, czy jest to problem z widokiem a kopiowaniem. – bmu

+0

Rozumiem teraz, że jest to czysta (a właściwie po prostu) różnica widzenia kontra kopia. Pierwsza metoda zapewnia tylko kopię, która jest zbiorem śmieci. Druga metoda zapewnia widok, dlatego ustawienie jest wykonywane na oryginalnej ramce danych. (patrz komentarze Dougala poniżej) –

Odpowiedz

15

Dokumentacja pandy mówi:

Wracając widok kontra kopia

Przepisy dotyczące kiedy widok na dane jest zwracany, są w całości zależne od NumPy. Ilekroć w procesie indeksowania uczestniczy tablica etykiet lub wektor boolowski, wynikiem będzie kopia. Przy indeksowaniu pojedynczym/skalarnym i krojeniu, np. df.ix [3: 6] lub df.ix [:, 'A'], widok zostanie zwrócony.

W df[df.key==1]['D'] najpierw wykonać logiczną segmentację (prowadzącego do kopii Dataframe), a następnie wybrać do kolumny D [ ''].

W df.D[df.key==1] = 3.4 najpierw wybierasz kolumnę, a następnie kroisz boolean na wynikowej Series.

To wydaje się mieć znaczenie, chociaż muszę przyznać, że jest to trochę sprzeczne z intuicją.

Edit: Różnica został zidentyfikowany przez Dougal patrz jego komentarz: W wersji 1, kopia wykonana jest jako metoda __getitem__ nazywa za logiczną krojenia. W wersji 2 dostępna jest tylko metoda __setitem__ - nie zwracanie kopii, a jedynie przypisywanie.

+0

To też myślałem na początku, ale musi być coś jeszcze. 'df [df.key == 1] = 1000' faktycznie przypisuje 1000 do wszystkich wartości w wycinku, więc nie może być kopią. Sądzę, że w metodzie __setattr__ lub __setitem__ dzieje się jakaś magia. – cxrodgers

+1

, ale jak zrobić boolean cięcia na wynikowej serii, to powinna być również kopia, prawda? Dlaczego zlecenie działa w ten sposób? –

+0

Spójrz na komentarz Dougals powyżej. W wersji 1 kopia jest wykonywana, ponieważ metoda __getitem __- jest wywoływana do krojenia boolean. W wersji 2 dostępna jest tylko metoda __setitem __-, więc nie zwraca ona kopii, a jedynie przypisuje. –

4

Jestem prawie pewien, że twoja pierwsza metoda zwraca kopię zamiast widoku, więc przypisanie jej nie powoduje zmiany oryginalnych danych. Nie jestem pewien, dlaczego tak się dzieje.

Wygląda na to, że jest on powiązany z kolejnością wybierania wierszy i kolumn, a NIE składnią do pobierania kolumn. Są zarówno praca:

df.D[df.key == 1] = 1 
df['D'][df.key == 1] = 1 

I żadna z tych prac:

df[df.key == 1]['D'] = 1 
df[df.key == 1].D = 1 

Od tego dowodu, chciałbym założyć, że plaster df[df.key == 1] wraca kopię. Ale tak nie jest! df[df.key == 1] = 0 faktycznie zmieni oryginalne dane, tak jakby były widokiem.

Więc nie jestem pewien. Mam wrażenie, że to zachowanie zmieniło się wraz z wersją pandy. Wydaje mi się, że pamiętam, że df.D użył do zwrócenia kopii i df ['D'] użytych do zwrócenia widoku, ale to już nie wydaje się być prawdziwe (pandy 0.10.0).

Jeśli chcesz pełniejszą odpowiedź, należy pisać na forum pystatsmodels: https://groups.google.com/forum/?fromgroups#!forum/pystatsmodels

+3

'df [df.key == 1]' _does_ faktycznie zwraca kopię (jak wskazuje odpowiedź Thorsten'a). Powód 'df [df.key == 1] = 0' modyfikuje oryginał, chociaż składnia jest nieco myląca, to w rzeczywistości nie robi tego samego; wersja nieprzypisująca nazywa '__getitem__' i wersją przydziału' __setitem__'. To tak, jakbyśmy mieli 'l = [0, 1, 2]', a następnie 'l [1]' zwraca int 1, ale 'l [1] = 5' modyfikuje oryginał. – Dougal