Jakich reguł używa Pandy do generowania widoku, a jakich kopii?

119

Jestem zdezorientowany regułami używanymi przez Pandas, gdy decyduję, że wybór z ramki danych jest kopią oryginalnej ramki danych lub widokiem oryginału.

Jeśli mam na przykład

df = pd.DataFrame(np.random.randn(8,8), columns=list('ABCDEFGH'), index=range(1,9))

Rozumiem, że queryzwraca kopię tak, że coś podobnego

foo = df.query('2 < index <= 5')
foo.loc[:,'E'] = 40

nie będzie miało wpływu na oryginalnym dataframe, df. Rozumiem również, że plasterki skalarne lub nazwane zwracają widok, więc przypisania do nich, takie jak

df.iloc[3] = 70

lub

df.ix[1,'B':'E'] = 222

zmieni się df. Ale gubię się, jeśli chodzi o bardziej skomplikowane sprawy. Na przykład,

df[df.C <= df.B] = 7654321

zmiany df, ale

df[df.C <= df.B].ix[:,'B':'E']

nie.

Czy jest jakaś prosta zasada, której używa Pandy, a której po prostu mi brakuje? Co się dzieje w tych konkretnych przypadkach; aw szczególności, jak zmienić wszystkie wartości (lub podzbiór wartości) w ramce danych, które spełniają określone zapytanie (jak próbuję to zrobić w ostatnim przykładzie powyżej)?


Uwaga: to nie to samo, co to pytanie ; i przeczytałem dokumentację , ale nie oświeciła mnie. Przeczytałem również „Powiązane” pytania na ten temat, ale nadal brakuje mi prostej reguły używanej przez Pandy i sposobu, w jaki zastosowałbym ją - na przykład - zmodyfikować wartości (lub podzbiór wartości) w ramce danych, która spełnia określone zapytanie.

orome
źródło

Odpowiedzi:

138

Oto zasady, późniejsza zmiana:

  • Wszystkie operacje generują kopię

  • Jeśli inplace=Truezostanie podany, zmodyfikuje w miejscu; tylko niektóre operacje to obsługują

  • Indeksator, który ustawia, np .loc/.iloc/.iat/.at. Ustawi w miejscu.

  • Indeksator, który pobiera obiekt o pojedynczym oznaczeniu, jest prawie zawsze widokiem (w zależności od układu pamięci może nie być, dlatego jest to niewiarygodne). Dotyczy to głównie wydajności. (przykład z góry dotyczy .query; to zawsze zwróci kopię w postaci oszacowanej przez numexpr)

  • Indeksator, który pobiera obiekt o wielu nazwach, jest zawsze kopią.

Twój przykład chained indexing

df[df.C <= df.B].loc[:,'B':'E']

nie ma gwarancji, że zadziała (dlatego nigdy nie powinieneś tego robić).

Zamiast tego zrób:

df.loc[df.C <= df.B, 'B':'E']

ponieważ jest to szybsze i zawsze będzie działać

Indeksowanie łańcuchowe to 2 oddzielne operacje w języku Python i dlatego nie można go wiarygodnie przechwycić przez pandy (często otrzymasz znak SettingWithCopyWarning, ale to też nie jest w 100% wykrywalne). Dokumentacja deweloperska , na którą wskazałeś, oferuje znacznie pełniejsze wyjaśnienie.

Jeff
źródło
3
.queryZAWSZE zwróci kopię z powodu tego, co robi (a nie widok), ponieważ jest oceniana przez n numexpr. Więc dodam to do „zasad”
Jeff
3
pandas polega na numpy w celu określenia, czy widok jest generowany. W przypadku pojedynczego dtype (który może być 1-d dla serii, 2-d dla ramki itp.). numpy może wygenerować widok; to zależy od tego, co kroisz; czasami można uzyskać widok, a czasami nie. pandy w ogóle nie polegają na tym fakcie, ponieważ nie zawsze jest oczywiste, czy widok jest generowany. ale to nie ma znaczenia, ponieważ loc nie polega na tym podczas ustawiania. Jednak podczas indeksowania łańcuchów jest to bardzo ważne (i dlatego indeksowanie łańcuchów jest złe)
Jeff,
3
Wielkie dzięki Jeff, twoja odpowiedź jest bardzo przydatna. Jakie jest Twoje źródło / odniesienie na ten temat?
Kamixave
4
Po pierwsze, dziękuję za wspaniałą pracę! Po drugie, jeśli masz wystarczająco dużo czasu, myślę, że byłoby wspaniale dodać akapit podobny do głównej odpowiedzi w dokumencie.
Kamixave,
2
z pewnością wymagałoby ściągnięcia prośby o dodanie / poprawienie dokumentów. idź po to.
Jeff,