Wie man Spaltenschnitte von Datenrahmen in Pandas nimmt


264

Ich lade einige maschinelle Lerndaten aus einer CSV-Datei. Die ersten beiden Spalten sind Beobachtungen und die verbleibenden Spalten sind Merkmale.

Derzeit mache ich Folgendes:

data = pandas.read_csv('mydata.csv')

das gibt so etwas wie:

data = pandas.DataFrame(np.random.rand(10,5), columns = list('abcde'))

Ich mag diesen Datenrahmen in zwei Datenrahmen schneiden: eine mit den Spalten enthalten aund bund man die Spalten enthält c, dund e.

Es ist nicht möglich, so etwas zu schreiben

observations = data[:'c']
features = data['c':]

Ich bin mir nicht sicher, was die beste Methode ist. Benötige ich eine pd.Panel?

Übrigens finde ich die Indizierung von Datenrahmen ziemlich inkonsistent: data['a']ist erlaubt, aber data[0]nicht. Auf der anderen Seite data['a':]ist das nicht erlaubt aber data[0:]. Gibt es dafür einen praktischen Grund? Dies ist wirklich verwirrend, wenn Spalten von Int indiziert werdendata[0] != data[0:1]


3
DataFrame ist von Natur aus ein diktartiges Objekt, wenn Sie [...] df ausführen. Es wurden jedoch einige Annehmlichkeiten df[5:10]hinzugefügt , z. B. zum Auswählen von Zeilen ( pandas.pydata.org/pandas-docs/stable/… )
Wes McKinney,

1
Was ist diese Inkonsistenz also eine Designentscheidung zugunsten der Bequemlichkeit? In Ordnung, aber für Anfänger muss es definitiv expliziter sein!
cpa

3
Die Designüberlegung zur Unterstützung des Komforts macht die Lernkurve sehr steil. Ich wünsche mir, dass es zu Beginn eine bessere Dokumentation gibt, die nur eine konsistente Oberfläche bietet. Konzentrieren Sie sich beispielsweise nur auf die ix-Oberfläche.
Yu Shen

Antworten:


242

2017 Antwort - Pandas 0.20: .ix ist veraltet. Verwenden Sie .loc

Siehe die Ablehnung in den Dokumenten

.locverwendet die beschriftungsbasierte Indizierung, um sowohl Zeilen als auch Spalten auszuwählen. Die Beschriftungen sind die Werte des Index oder der Spalten. Das Schneiden mit .locenthält das letzte Element.

Nehmen wir an , wir einen Datenrahmen mit den folgenden Spalten:
foo, bar, quz, ant, cat, sat, dat.

# selects all rows and all columns beginning at 'foo' up to and including 'sat'
df.loc[:, 'foo':'sat']
# foo bar quz ant cat sat

.locAkzeptiert dieselbe Slice-Notation wie Python-Listen für Zeilen und Spalten. Slice Notation iststart:stop:step

# slice from 'foo' to 'cat' by every 2nd column
df.loc[:, 'foo':'cat':2]
# foo quz cat

# slice from the beginning to 'bar'
df.loc[:, :'bar']
# foo bar

# slice from 'quz' to the end by 3
df.loc[:, 'quz'::3]
# quz sat

# attempt from 'sat' to 'bar'
df.loc[:, 'sat':'bar']
# no columns returned

# slice from 'sat' to 'bar'
df.loc[:, 'sat':'bar':-1]
sat cat ant quz bar

# slice notation is syntatic sugar for the slice function
# slice from 'quz' to the end by 2 with slice function
df.loc[:, slice('quz',None, 2)]
# quz cat dat

# select specific columns with a list
# select columns foo, bar and dat
df.loc[:, ['foo','bar','dat']]
# foo bar dat

Sie können nach Zeilen und Spalten schneiden. Zum Beispiel, wenn Sie haben 5 Zeilen mit Etiketten v, w, x, y,z

# slice from 'w' to 'y' and 'foo' to 'ant' by 3
df.loc['w':'y', 'foo':'ant':3]
#    foo ant
# w
# x
# y

Wenn Sie mit Lambda Row anwenden, wie in: df['newcol'] = df.apply(lambda row: myfunc(row), axis=1) dann können Sie in myfunc(row){... verwenden row['foo':'ant']. Zum Beispiel (gemäß dieser StackOverflow-Antwort ) können Sie im Inneren myfuncbewerten, ob einer dieser Punkte nicht numerisch ist:row['foo':'ant'].apply(lambda x: isinstance(x, str)).any()
Pashute

4
.ilocsollte jetzt anstelle von verwendet werden .loc. Repariere das und ich werde es positiv bewerten.
Craned

1
@craned - das ist nicht richtig. Aus der Pandas-Dokumentation: .loc basiert hauptsächlich auf Labels, kann aber auch mit einem booleschen Array verwendet werden. .loc löst KeyError aus, wenn die Elemente nicht gefunden werden. Eine ähnliche Aussage wird über .iloc gemacht, außer dass sie sich speziell auf indexbasiertes Slicing bezieht. Mit anderen Worten, in diesem Beispiel verwendete er die markenbasierte Indizierung und .loc ist die richtige Wahl (im Grunde die einzige Wahl). Wenn Sie beispielsweise nach Position-Zeilen 5:10 schneiden möchten, verwenden Sie .iloc
user2103050

149

Hinweis: .ix ist seit Pandas v0.20 veraltet. Sie sollten stattdessen .locoder verwenden .iloc, falls zutreffend.

Auf den DataFrame.ix-Index möchten Sie zugreifen. Es ist ein wenig verwirrend (ich stimme zu, dass die Pandas-Indizierung manchmal verwirrend ist!), Aber das Folgende scheint zu tun, was Sie wollen:

>>> df = DataFrame(np.random.rand(4,5), columns = list('abcde'))
>>> df.ix[:,'b':]
      b         c         d         e
0  0.418762  0.042369  0.869203  0.972314
1  0.991058  0.510228  0.594784  0.534366
2  0.407472  0.259811  0.396664  0.894202
3  0.726168  0.139531  0.324932  0.906575

Dabei wird .ix [Zeilen-, Spalten-] interpretiert. Weitere Informationen zur Pandas-Indizierung finden Sie hier: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-advanced


5
Vorsicht, dass Bereiche in Pandas beide Endpunkte umfassen, dh>>>data.ix[:, 'a':'c'] a b c 0 0.859192 0.881433 0.843624 1 0.744979 0.427986 0.177159
Grashüpfer

21
Mehrere Spalten können wie df.ix[:,[0,3,4]]
folgt übergeben werden

3
@Karmel: In der obigen Ausgabe sieht es nach einem Kopier- / Einfügefehler aus. Vielleicht hast du gemeint df.ix[:,'b':'e']?
ChaimG

6
Es ist besser zu verwenden locals ix: stackoverflow.com/a/31593712/4323
John Zwinck

5
Alte Antworten wie diese müssen gelöscht werden. .ix ist veraltet und sollte niemals verwendet werden.
Ted Petrou

75

Nehmen wir als Beispiel den Titanic-Datensatz aus dem Seaborn-Paket

# Load dataset (pip install seaborn)
>> import seaborn.apionly as sns
>> titanic = sns.load_dataset('titanic')

unter Verwendung der Spaltennamen

>> titanic.loc[:,['sex','age','fare']]

unter Verwendung der Spaltenindizes

>> titanic.iloc[:,[2,3,6]]

mit ix (älter als Pandas <.20 Version)

>> titanic.ix[:,[‘sex’,’age’,’fare’]]

oder

>> titanic.ix[:,[2,3,6]]

mit der Reindex-Methode

>> titanic.reindex(columns=['sex','age','fare'])

6
In Pandas 0,20: .ixist veraltet.
Shihe Zhang

Passing list-likes to .loc or [] with any missing label will raise KeyError in the future, you can use .reindex() as an alternative.df.loc[:, some_list_of_columns]
Verfallswarnung

35

Auch gegeben ein DataFrame

Daten

Wenn Sie wie in Ihrem Beispiel nur die Spalten a und d extrahieren möchten (z. B. die 1. und 4. Spalte), benötigen Sie iloc mothod aus dem pandas-Datenrahmen und können sehr effektiv verwendet werden. Sie müssen lediglich den Index der Spalten kennen, die Sie extrahieren möchten. Beispielsweise:

>>> data.iloc[:,[0,3]]

werde dir geben

          a         d
0  0.883283  0.100975
1  0.614313  0.221731
2  0.438963  0.224361
3  0.466078  0.703347
4  0.955285  0.114033
5  0.268443  0.416996
6  0.613241  0.327548
7  0.370784  0.359159
8  0.692708  0.659410
9  0.806624  0.875476

25

Sie können entlang der Spalten von a schneiden, DataFrameindem Sie auf die Namen jeder Spalte in einer Liste verweisen, wie folgt:

data = pandas.DataFrame(np.random.rand(10,5), columns = list('abcde'))
data_ab = data[list('ab')]
data_cde = data[list('cde')]

Wenn ich also alle Daten ab Spalte 'b' haben möchte, muss ich den Index von 'b' in data.columns finden und data [data.columns [1:]] ausführen? Das ist die kanonische Arbeitsweise?
cpa

1
Sie meinen, Sie möchten alle Spalten ab 'b' auswählen?
Brendan Wood

Ja, oder alle Spalten in einem bestimmten Bereich auswählen.
cpa

Ich bin selbst ziemlich neu in Pandas, daher kann ich nicht darüber sprechen, was als kanonisch angesehen wird. Ich würde es tun, wie Sie sagten, aber die get_locFunktion on verwenden data.columns, um den Index der Spalte 'b' oder was auch immer zu bestimmen.
Brendan Wood

20

Und wenn Sie hierher gekommen sind, um zwei Spaltenbereiche zu schneiden und zu kombinieren (wie ich), können Sie so etwas tun

op = df[list(df.columns[0:899]) + list(df.columns[3593:])]
print op

Dadurch wird ein neuer Datenrahmen mit den ersten 900 Spalten und (allen) Spalten> 3593 erstellt (vorausgesetzt, Sie haben etwa 4000 Spalten in Ihrem Datensatz).


Großartig, jemand hat das ausprobiert ... Ich habe mich gefragt, dieses 0: 899, das die ersten 900 Spalten erhält. Warum haben sie es so gemacht? Das fühlt sich überhaupt nicht nach Python an. Wenn Sie Bereiche in Python verwenden, ist es immer 'bis' nicht 'bis und eingeschlossen'
zwep

14

Hier erfahren Sie, wie Sie verschiedene Methoden zum selektiven Spaltenschneiden verwenden können, einschließlich selektives Etikettenbasiertes, indexbasiertes und selektives Spaltenschneiden.

In [37]: import pandas as pd    
In [38]: import numpy as np
In [43]: df = pd.DataFrame(np.random.rand(4,7), columns = list('abcdefg'))

In [44]: df
Out[44]: 
          a         b         c         d         e         f         g
0  0.409038  0.745497  0.890767  0.945890  0.014655  0.458070  0.786633
1  0.570642  0.181552  0.794599  0.036340  0.907011  0.655237  0.735268
2  0.568440  0.501638  0.186635  0.441445  0.703312  0.187447  0.604305
3  0.679125  0.642817  0.697628  0.391686  0.698381  0.936899  0.101806

In [45]: df.loc[:, ["a", "b", "c"]] ## label based selective column slicing 
Out[45]: 
          a         b         c
0  0.409038  0.745497  0.890767
1  0.570642  0.181552  0.794599
2  0.568440  0.501638  0.186635
3  0.679125  0.642817  0.697628

In [46]: df.loc[:, "a":"c"] ## label based column ranges slicing 
Out[46]: 
          a         b         c
0  0.409038  0.745497  0.890767
1  0.570642  0.181552  0.794599
2  0.568440  0.501638  0.186635
3  0.679125  0.642817  0.697628

In [47]: df.iloc[:, 0:3] ## index based column ranges slicing 
Out[47]: 
          a         b         c
0  0.409038  0.745497  0.890767
1  0.570642  0.181552  0.794599
2  0.568440  0.501638  0.186635
3  0.679125  0.642817  0.697628

### with 2 different column ranges, index based slicing: 
In [49]: df[df.columns[0:1].tolist() + df.columns[1:3].tolist()]
Out[49]: 
          a         b         c
0  0.409038  0.745497  0.890767
1  0.570642  0.181552  0.794599
2  0.568440  0.501638  0.186635
3  0.679125  0.642817  0.697628

Bitte versuchen Sie zu vermeiden, nur Code als Antwort auszugeben, und versuchen Sie zu erklären, was er tut und warum. Ihr Code ist möglicherweise nicht offensichtlich für Personen, die nicht über die entsprechende Codierungserfahrung verfügen. Bitte bearbeiten Sie Ihre Antwort, um Klarstellung und Kontext aufzunehmen, und versuchen Sie, Einschränkungen, Annahmen oder Vereinfachungen in Ihrer Antwort zu erwähnen.
Am 19.

1

Sein Äquivalent

 >>> print(df2.loc[140:160,['Relevance','Title']])
 >>> print(df2.ix[140:160,[3,7]])

1

Wenn der Datenrahmen so aussieht:

group         name      count
fruit         apple     90
fruit         banana    150
fruit         orange    130
vegetable     broccoli  80
vegetable     kale      70
vegetable     lettuce   125

und OUTPUT könnte sein wie

   group    name  count
0  fruit   apple     90
1  fruit  banana    150
2  fruit  orange    130

Wenn Sie den logischen Operator np.logical_not verwenden

df[np.logical_not(df['group'] == 'vegetable')]

mehr über

https://docs.scipy.org/doc/numpy-1.13.0/reference/routines.logic.html

andere logische Operatoren

  1. logisch_und (x1, x2, / [, out, where, ...]) Berechnen Sie den Wahrheitswert von x1 UND x2 elementweise.

  2. logisch_oder (x1, x2, / [, out, where, casting, ...]) Berechnen Sie den Wahrheitswert von x1 ODER x2 elementweise.

  3. logisch_not (x, / [, out, where, casting, ...]) Berechnen Sie den Wahrheitswert von NOT x elementweise.
  4. logischer_xor (x1, x2, / [, out, where, ..]) Berechnen Sie den Wahrheitswert von x1 XOR x2 elementweise.

0

Eine andere Möglichkeit, eine Teilmenge von Spalten aus Ihrem DataFrame abzurufen, unter der Annahme, dass Sie alle Zeilen möchten, besteht darin, Folgendes zu tun:
data[['a','b']]und data[['c','d','e']]
Wenn Sie numerische Spaltenindizes verwenden möchten, können Sie Folgendes tun:
data[data.columns[:2]]unddata[data.columns[2:]]

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.