2014-12-08 21 views
8

Was ist der Unterschied zwischen:pandas dataframe view vs kopieren, wie kann ich sagen?

Pandas df.loc[:,('col_a','col_b')]

und

df.loc[:,['col_a','col_b']]

Der Link unten nicht das letztere nicht erwähnt, obwohl es funktioniert. Ziehen beide einen Blick? Zieht der erste eine Ansicht und der zweite eine Kopie? Liebe, Pandas zu lernen.

http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy

Dank

+2

beide sind die gleichen und werden eine Ansicht – EdChum

+1

zurückgeben und wie können Sie sagen, außer ein Pandas Jedi zu sein – user3659451

+0

Die Dokumentation besagt, dies ist so, plus, wenn Sie etwas versuchen wie 'df [:] [['a', 'b']] = 5 'es wird eine Warnung ausgelöst – EdChum

Antwort

20

Wenn Ihr Datenrahmen einen einfachen Spaltenindex hat, dann gibt es keinen Unterschied. Zum Beispiel

In [8]: df = pd.DataFrame(np.arange(12).reshape(4,3), columns=list('ABC')) 

In [9]: df.loc[:, ['A','B']] 
Out[9]: 
    A B 
0 0 1 
1 3 4 
2 6 7 
3 9 10 

In [10]: df.loc[:, ('A','B')] 
Out[10]: 
    A B 
0 0 1 
1 3 4 
2 6 7 
3 9 10 

Aber wenn der Datenrahmen einen Multiindex hat, kann es ein großer Unterschied sein:

df = pd.DataFrame(np.random.randint(10, size=(5,4)), 
        columns=pd.MultiIndex.from_arrays([['foo']*2+['bar']*2, 
                list('ABAB')]), 
        index=pd.MultiIndex.from_arrays([['baz']*2+['qux']*3, 
                list('CDCDC')])) 

#  foo bar 
#   A B A B 
# baz C 7 9 9 9 
#  D 7 5 5 4 
# qux C 5 0 5 1 
#  D 1 7 7 4 
#  C 6 4 3 5 

In [27]: df.loc[:, ('foo','B')] 
Out[27]: 
baz C 9 
    D 5 
qux C 0 
    D 7 
    C 4 
Name: (foo, B), dtype: int64 

In [28]: df.loc[:, ['foo','B']] 
KeyError: 'MultiIndex Slicing requires the index to be fully lexsorted tuple len (1), lexsort depth (0)' 

Die KeyError sagt, dass der Multiindex lexsorted werden muss. Wenn wir das tun, erhalten wir immer noch ein anderes Ergebnis:

In [29]: df.sortlevel(axis=1).loc[:, ('foo','B')] 
Out[29]: 
baz C 9 
    D 5 
qux C 0 
    D 7 
    C 4 
Name: (foo, B), dtype: int64 

In [30]: df.sortlevel(axis=1).loc[:, ['foo','B']] 
Out[30]: 
     foo 
     A B 
baz C 7 9 
    D 7 5 
qux C 5 0 
    D 1 7 
    C 6 4 

Warum ist das? df.sortlevel(axis=1).loc[:, ('foo','B')] wählt die Spalte aus, in der die erste Spaltenebene foo und die zweite Spaltenebene B ist.

Im Gegensatz dazu wählt df.sortlevel(axis=1).loc[:, ['foo','B']] die Spalten aus, in denen die erste Spalte entweder foo oder B ist. In Bezug auf die erste Spaltebene gibt es keine B Spalten, aber es gibt zwei foo Spalten.

denke ich, das Funktionsprinzip mit Pandas, dass, wenn Sie df.loc[...] als ein Ausdruck verwenden, sollten Sie davon ausgehen, df.loc kann eine Kopie oder eine Ansicht zurückkehren. In den Pandas-Dokumenten sind keine Regeln angegeben, die Sie erwarten sollten. Wenn Sie jedoch eine Zuordnung der Form

df.loc[...] = value 

dann machen Sie Pandas vertrauen df selbst zu verändern.

Der Grund, warum die Dokumentation über den Unterschied zwischen den Ansichten und Kopien warnt, so dass Sie

df.loc[...][...] = value 

Hier kennt die Gefahr der Verwendung von Ketten Zuordnungen der Form sind, Pandas df.loc[...] zuerst auswertet, die sein kann, eine Ansicht oder eine Kopie. Nun, wenn es eine Kopie ist, dann

df.loc[...][...] = value 

ist eine Kopie eines bestimmten Teils der df zu verändern, und hat somit keinen Einfluss auf df selbst.Um die Verletzung zu beleidigen, ist auch der Effekt auf die Kopie verloren, da es keine Verweise auf die Kopie gibt und somit keine Möglichkeit besteht, auf die Kopie zuzugreifen, nachdem die Zuweisungsanweisung abgeschlossen ist, und (zumindest in CPython) daher bald Müll gesammelt werden.


Ich weiß nicht, von einem praktischen todsicheren a priori Art und Weise zu bestimmen, ob df.loc[...] eine Ansicht oder eine Kopie zurückkehren wird.

Allerdings gibt es einige Faustregeln, die Ihre Intuition leiten helfen können (aber beachten Sie, dass wir hier über Implementierungsdetails sprechen, so gibt es keine Garantie, dass Pandas auf diese Weise in der Zukunft verhalten muss):

  • Wenn der resultierende NDFrame nicht als Basisscheibe des zugrunde liegenden NumPy-Arrays ausgedrückt werden kann, handelt es sich wahrscheinlich um eine Kopie. Somit führt eine Auswahl von beliebigen Zeilen oder Spalten zu einer Kopie. Eine Auswahl von sequentiellen Zeilen und/oder sequenziellen Spalten (die als Slice ausgedrückt werden können) kann eine Ansicht zurückgeben.
  • Wenn der resultierende NDFrame Spalten verschiedener Dtypes enthält, gibt df.loc wahrscheinlich erneut eine Kopie zurück.

Allerdings gibt es eine einfache Möglichkeit, zu bestimmen, ob x = df.loc[..] eine Ansicht ist ein posteriori: Einfach sehen, ob ein Wert in x Ändern df auswirkt. Wenn dies der Fall ist, ist es eine Ansicht, wenn nicht, ist x eine Kopie.

+1

Wenn wir einfach einen Ausdruck wie 'df.loc [..]' verwenden und es sich herausstellt, dass es sich um eine Kopie handelt, warum sollte etwas wie 'df.loc [..] = ... 'wird irgendwie zur Ansicht? Sieht fischig aus. Aber vielen Dank für Ihre Erklärung. Es fühlt sich jetzt viel klarer an. – user3659451

+3

Bei der Verwendung als Ausdruck ruft 'df.loc [...]' 'df.loc .__ getitem __ (...)' auf. Bei der Verwendung als Zuweisung ruft 'df.loc [...] = value' 'df.loc .__ setitem __ (..., value)' auf. Die Methode "__getitem__" kann eine Ansicht oder eine Kopie zurückgeben. Aber die '__setitem__' Methode wird immer' df' selbst modifizieren. Schließlich ist das das einzig Vernünftige für ein "__setitem__". – unutbu

+0

@ user3659451 nicht darüber besorgt sein, ob etwas eine Sicht ist. Es gibt nur bestimmte Umstände, unter denen es * eine * Ansicht sein kann, aber KEINE sind garantiert. Verwenden Sie einfach '' loc'' um zu setzen und alles wird gut. Ansichten sind eine Funktion des Speicherlayouts der zugrunde liegenden Daten und ihrer Auswahl. – Jeff