Auswählen mehrerer Spalten in einem Pandas-Datenrahmen

1112

Ich habe Daten in verschiedenen Spalten, weiß aber nicht, wie ich sie extrahieren soll, um sie in einer anderen Variablen zu speichern.

index  a   b   c
1      2   3   4
2      3   4   5

Wie wähle ich 'a', 'b'und es um df1 retten?

Ich habe es versucht

df1 = df['a':'b']
df1 = df.ix[:, 'a':'b']

Keiner scheint zu funktionieren.

user1234440
quelle
2
Sie möchten nie verwenden, .ixda es mehrdeutig ist. Verwenden Sie .ilocoder .locwenn Sie müssen.
Acumenus
1
Gibt es eine Möglichkeit, dies ohne Bezugnahme auf die Headernamen zu tun? Wie in R kann ich es so machen: > csvtable_imp_1 <- csvtable_imp[0:6]und es wählt den Delta-Betrag der ersten Spalten zwischen 0 und 6 aus. Alles, was ich tun musste, war, die CSV-Tabelle so zu lesen, wie sie durch die readr lib begrenzt ist.
MichaelR
Ich habe ein bisschen mehr damit gearbeitet. Ich habe etwas gefunden, das wie gewünscht funktioniert hat. Standardmäßig wird die Anzahl der Zeichen und nicht die Spalten ausgewählt. infile_1 = largefile_stay.ix[:,0:6]
MichaelR
3
Für diejenigen, die so spät stolpern, ixist jetzt veraltet. Pandas empfiehlt entweder: loc(Label-basierte Indizierung) oder iloc(Positions-basierte Indizierung).
ZaydH

Antworten:

1768

Die Spaltennamen (die Zeichenfolgen sind) können nicht auf die von Ihnen versuchte Weise in Scheiben geschnitten werden.

Hier haben Sie einige Möglichkeiten. Wenn Sie aus dem Kontext wissen, welche Variablen Sie herausschneiden möchten, können Sie nur eine Ansicht dieser Spalten zurückgeben, indem Sie eine Liste an die __getitem__Syntax (die []) übergeben.

df1 = df[['a','b']]

Wenn es wichtig ist, sie numerisch und nicht nach ihrem Namen zu indizieren (sagen wir, Ihr Code sollte dies automatisch tun, ohne die Namen der ersten beiden Spalten zu kennen), können Sie dies stattdessen tun:

df1 = df.iloc[:,0:2] # Remember that Python does not slice inclusive of the ending index.

Darüber hinaus sollten Sie sich mit der Idee einer Ansicht in ein Pandas-Objekt im Vergleich zu einer Kopie dieses Objekts vertraut machen. Die erste der oben genannten Methoden gibt eine neue Kopie im Speicher des gewünschten Unterobjekts (der gewünschten Slices) zurück.

Manchmal gibt es jedoch Indizierungskonventionen in Pandas, die dies nicht tun und Ihnen stattdessen eine neue Variable geben, die sich nur auf denselben Speicherbereich bezieht wie das Unterobjekt oder Slice im ursprünglichen Objekt. Dies geschieht bei der zweiten Art der Indizierung, sodass Sie sie mit der copy()Funktion ändern können, um eine reguläre Kopie zu erhalten. Wenn dies geschieht, kann das Ändern des Ihrer Meinung nach geschnittenen Objekts manchmal das ursprüngliche Objekt ändern. Es ist immer gut, darauf zu achten.

df1 = df.iloc[0,0:2].copy() # To avoid the case where changing df1 also changes df

Zur Verwendung ilocmüssen Sie die Spaltenpositionen (oder Indizes) kennen. Da sich die Spaltenpositionen ändern können, können Sie anstelle der hartcodierten Indizes iloczusammen mit der get_locFunktion der columnsMethode des Datenrahmenobjekts Spaltenindizes abrufen.

{df.columns.get_loc(c):c for idx, c in enumerate(df.columns)}

Jetzt können Sie dieses Wörterbuch verwenden, um über Namen und Verwendung auf Spalten zuzugreifen iloc.

ely
quelle
192
Hinweis: df[['a','b']]produziert eine Kopie
Wes McKinney
1
Ja, das war in meiner Antwort impliziert. Die etwas über die Kopie nur für den Gebrauch von , ix[]wenn Sie es vorziehen , zu verwenden , ix[]aus irgendeinem Grund.
ely
1
ixindiziert Zeilen, keine Spalten. Ich dachte, das OP wollte Spalten.
Kochfelder
9
ixAkzeptiert Slice-Argumente, sodass Sie auch Spalten abrufen können. Zum Beispiel df.ix[0:2, 0:2]wird das obere linke 2x2-Subarray genau wie bei einer NumPy-Matrix abgerufen (natürlich abhängig von Ihren Spaltennamen). Sie können die Slice-Syntax sogar für Zeichenfolgennamen der Spalten verwenden, z df.ix[0, 'Col1':'Col5']. Dadurch werden alle Spalten abgerufen, die zufällig zwischen Col1und Col5im df.columnsArray angeordnet sind. Es ist falsch zu sagen, dass ixZeilen indiziert werden. Das ist nur die grundlegendste Verwendung. Es unterstützt auch viel mehr Indizierung als das. Also, ixist ganz allgemein für diese Frage.
ely
7
@ AndrewCassidy Nie wieder .ix verwenden. Wenn Sie mit Ganzzahlen schneiden möchten, verwenden Sie .ilocgenau wie Python-Listen die letzte Position.
Ted Petrou
133

Ab der Version 0.11.0, Spalten kann in der Art und Weise Sie mit der versucht , in Scheiben geschnitten .locIndexer:

df.loc[:, 'C':'E']

ist äquivalent zu

df[['C', 'D', 'E']]  # or df.loc[:, ['C', 'D', 'E']]

und gibt Spalten Cdurch zurück E.


Eine Demo zu einem zufällig generierten DataFrame:

import pandas as pd
import numpy as np
np.random.seed(5)
df = pd.DataFrame(np.random.randint(100, size=(100, 6)), 
                  columns=list('ABCDEF'), 
                  index=['R{}'.format(i) for i in range(100)])
df.head()

Out: 
     A   B   C   D   E   F
R0  99  78  61  16  73   8
R1  62  27  30  80   7  76
R2  15  53  80  27  44  77
R3  75  65  47  30  84  86
R4  18   9  41  62   1  82

So rufen Sie die Spalten von C nach E ab (beachten Sie, dass im Gegensatz zum Integer-Slicing 'E' in den Spalten enthalten ist):

df.loc[:, 'C':'E']

Out: 
      C   D   E
R0   61  16  73
R1   30  80   7
R2   80  27  44
R3   47  30  84
R4   41  62   1
R5    5  58   0
...

Gleiches gilt für die Auswahl von Zeilen anhand von Beschriftungen. Holen Sie sich die Zeilen 'R6' bis 'R10' aus diesen Spalten:

df.loc['R6':'R10', 'C':'E']

Out: 
      C   D   E
R6   51  27  31
R7   83  19  18
R8   11  67  65
R9   78  27  29
R10   7  16  94

.locAkzeptiert auch ein boolesches Array, sodass Sie die Spalten auswählen können, deren entsprechender Eintrag im Array lautet True. Zum Beispiel df.columns.isin(list('BCD'))kehrt array([False, True, True, True, False, False], dtype=bool)- Wahr , wenn die Spaltennamen in der Liste enthalten sind ['B', 'C', 'D']; Sonst falsch.

df.loc[:, df.columns.isin(list('BCD'))]

Out: 
      B   C   D
R0   78  61  16
R1   27  30  80
R2   53  80  27
R3   65  47  30
R4    9  41  62
R5   78   5  58
...
Ayhan
quelle
110

Angenommen, Ihre Spaltennamen ( df.columns) sind ['index','a','b','c'], dann befinden sich die gewünschten Daten in der 3. und 4. Spalte. Wenn Sie ihre Namen bei der Ausführung Ihres Skripts nicht kennen, können Sie dies tun

newdf = df[df.columns[2:4]] # Remember, Python is 0-offset! The "3rd" entry is at slot 2.

Als EMS in weist darauf hin , seine Antwort , df.ixScheiben Spalten etwas prägnanten, aber die .columnsSlicing - Schnittstelle könnte natürlicher sein , weil es die Vanille-1-D Python Liste Indizierung / Slicing - Syntax verwendet.

WARN: 'index'ist ein schlechter Name für eine DataFrameSpalte. Dieselbe Bezeichnung wird auch für das reale df.indexAttribut, ein IndexArray, verwendet. Ihre Spalte wird also von zurückgegeben, df['index']und der echte DataFrame-Index wird von zurückgegeben df.index. An Indexist eine spezielle Art der SeriesOptimierung für die Suche nach den Werten seiner Elemente. Für df.index dient es zum Nachschlagen von Zeilen anhand ihrer Bezeichnung. Dieses df.columnsAttribut ist auch ein pd.IndexArray zum Nachschlagen von Spalten anhand ihrer Beschriftungen.

Kochfelder
quelle
3
Wie ich in meinem Kommentar oben bemerkt habe, .ixist nicht nur für Zeilen. Es dient zum allgemeinen Schneiden und kann zum mehrdimensionalen Schneiden verwendet werden. Es ist im Grunde nur eine Schnittstelle zu NumPys üblicher __getitem__Syntax. Das heißt, Sie können ein Spalten-Slicing-Problem leicht in ein Zeilen-Slicing-Problem umwandeln, indem Sie einfach eine Transponierungsoperation anwenden df.T. Ihr Beispiel verwendet columns[1:3], was ein wenig irreführend ist. Das Ergebnis von columnsist a Series; Achten Sie darauf, es nicht nur wie ein Array zu behandeln. Außerdem sollten Sie es wahrscheinlich so ändern, dass es columns[2:3]mit Ihrem "3. und 4." Kommentar übereinstimmt.
ely
@ Mr.F: Mein [2:4]ist richtig. Dein [2:3]ist falsch. Die Verwendung der Standard-Python-Slicing-Notation zum Generieren einer Sequenz / Serie ist IMO nicht irreführend. Aber ich mag es, wenn Sie die DataFrame-Schnittstelle umgehen, um mit auf das zugrunde liegende numpy-Array zuzugreifen ix.
Kochfelder
Sie sind in diesem Fall richtig, aber der Punkt, den ich ansprechen wollte, ist, dass das Schneiden mit Beschriftungen in Pandas im Allgemeinen den Slice-Endpunkt einschließt (oder zumindest war dies das Verhalten in den meisten früheren Pandas-Versionen). Wenn Sie es also abrufen df.columnsund nach Beschriftung aufteilen möchten, haben Sie eine andere Slice-Semantik als wenn Sie es nach ganzzahliger Indexposition aufteilen . Ich habe es in meinem vorherigen Kommentar definitiv nicht gut erklärt.
ely
Ahh, jetzt verstehe ich deinen Standpunkt. Ich habe vergessen, dass columnses sich um eine unveränderliche Serie handelt, und der Getter wurde überschrieben, um Labels als Indizes zu verwenden. Vielen Dank, dass Sie sich die Zeit genommen haben, dies zu klären.
Kochfelder
2
Beachten Sie die Verfallswarnung: .ix ist veraltet. Daher ist dies sinnvoll: newdf = df [df.columns [2: 4]]
Martien Lubberink
64
In [39]: df
Out[39]: 
   index  a  b  c
0      1  2  3  4
1      2  3  4  5

In [40]: df1 = df[['b', 'c']]

In [41]: df1
Out[41]: 
   b  c
0  3  4
1  4  5
Wes McKinney
quelle
1
Was wäre, wenn ich die Spalte umbenennen wollte, zum Beispiel so etwas wie: df[['b as foo', 'c as bar']Die Ausgabe benennt Spalte bals foound Spalte cals um bar?
Kuanb
5
df[['b', 'c']].rename(columns = {'b' : 'foo', 'c' : 'bar'})
Greg
61

Mir ist klar, dass diese Frage ziemlich alt ist, aber in der neuesten Version von Pandas gibt es eine einfache Möglichkeit, genau dies zu tun. Spaltennamen (die Zeichenfolgen sind) können nach Belieben in Scheiben geschnitten werden.

columns = ['b', 'c']
df1 = pd.DataFrame(df, columns=columns)
Zerovektor
quelle
6
Dies kann nur bei der Erstellung erfolgen. Die Frage ist, ob Sie es bereits in einem Datenrahmen haben.
Banjocat
2
@ Banjocat, es funktioniert mit einem vorhandenen Datenrahmen
mhery
23

Sie können eine Liste der zu löschenden Spalten bereitstellen und den DataFrame nur mit den Spalten zurückgeben, die mithilfe der drop()Funktion in einem Pandas DataFrame benötigt werden .

Nur sagen

colsToDrop = ['a']
df.drop(colsToDrop, axis=1)

würde einen DataFrame mit nur den Spalten bund zurückgeben c.

Die dropMethode ist hier dokumentiert .

Muthu Chithambara Jothi
quelle
23

Mit Pandas,

mit Spaltennamen

dataframe[['column1','column2']]

nach iloc und bestimmten Spalten mit Indexnummer auswählen:

dataframe.iloc[:,[1,2]]

mit loc können Spaltennamen wie verwendet werden

dataframe.loc[:,['column1','column2']]
Vivek Ananthan
quelle
20

Ich fand diese Methode sehr nützlich:

# iloc[row slicing, column slicing]
surveys_df.iloc [0:3, 1:4]

Weitere Details finden Sie hier

Alvis
quelle
Wie würden Sie beispielsweise nur die Spalten 2 und 5 nehmen?
324
1
Das wäre surveys_df.iloc [:, [2,5]]dann.
Julian Gorfer
15

Ab 0.21.0 wird die Verwendung von .locoder []mit einer Liste mit einem oder mehreren fehlenden Labels zugunsten von abgelehnt .reindex. Die Antwort auf Ihre Frage lautet also:

df1 = df.reindex(columns=['b','c'])

In früheren Versionen .loc[list-of-labels]würde die Verwendung funktionieren, solange mindestens einer der Schlüssel gefunden wurde (andernfalls würde a ausgelöst KeyError). Dieses Verhalten ist veraltet und zeigt jetzt eine Warnmeldung an. Die empfohlene Alternative ist die Verwendung .reindex().

Weitere Informationen finden Sie unter Indizieren und Auswählen von Daten

tozCSS
quelle
10

Sie können Pandas verwenden. Ich erstelle den DataFrame:

    import pandas as pd
    df = pd.DataFrame([[1, 2,5], [5,4, 5], [7,7, 8], [7,6,9]], 
                      index=['Jane', 'Peter','Alex','Ann'],
                      columns=['Test_1', 'Test_2', 'Test_3'])

Der DataFrame:

           Test_1  Test_2  Test_3
    Jane        1       2       5
    Peter       5       4       5
    Alex        7       7       8
    Ann         7       6       9

So wählen Sie eine oder mehrere Spalten nach Namen aus:

    df[['Test_1','Test_3']]

           Test_1  Test_3
    Jane        1       5
    Peter       5       5
    Alex        7       8
    Ann         7       9

Sie können auch verwenden:

    df.Test_2

Und du bekommst eine Kolumne Test_2

    Jane     2
    Peter    4
    Alex     7
    Ann      6

Sie können aus diesen Zeilen auch Spalten und Zeilen auswählen .loc(). Dies wird als "Schneiden" bezeichnet . Beachten Sie, dass ich von Spalte Test_1zu Spalte nehmeTest_3

    df.loc[:,'Test_1':'Test_3']

Das "Slice" ist:

            Test_1  Test_2  Test_3
     Jane        1       2       5
     Peter       5       4       5
     Alex        7       7       8
     Ann         7       6       9

Und wenn Sie nur wollen Peterund Annaus Spalten Test_1und Test_3:

    df.loc[['Peter', 'Ann'],['Test_1','Test_3']]

Du erhältst:

           Test_1  Test_3
    Peter       5       5
    Ann         7       9
pink.slash
quelle
8

Wenn Sie ein Element nach Zeilenindex und Spaltennamen erhalten möchten, können Sie dies wie folgt tun df['b'][0]. Es ist so einfach wie Sie sich vorstellen können.

Oder Sie können eine df.ix[0,'b']gemischte Verwendung von Index und Label verwenden.

Hinweis: Da v0.20 ixzugunsten von loc/ veraltet ist iloc.

W.Perrin
quelle
6

Ein anderer und einfacher Ansatz: Zeilen iterieren

mit iterows

 df1= pd.DataFrame() #creating an empty dataframe
 for index,i in df.iterrows():
    df1.loc[index,'A']=df.loc[index,'A']
    df1.loc[index,'B']=df.loc[index,'B']
    df1.head()
Ankita
quelle
5
Bitte empfehlen Sie nicht die Verwendung von iterrows (). Es ist ein eklatanter Wegbereiter für das schlimmste Anti-Muster in der Geschichte der Pandas.
CS95
Könnten Sie bitte erklären, was Sie unter "schlechtestem Anti-Muster" verstehen?
Ankita
1
IMHO sollte iterrows () die letzte Option sein, wenn Pandas verwendet werden.
Elf
5

Die verschiedenen Ansätze, die in den obigen Antworten diskutiert wurden, basieren auf der Annahme, dass entweder der Benutzer Spaltenindizes kennt, auf die er fallen oder eine Teilmenge festlegen soll, oder dass der Benutzer einen Datenrahmen unter Verwendung eines Spaltenbereichs (beispielsweise zwischen 'C': 'E') unterteilen möchte. . pandas.DataFrame.drop () ist sicherlich eine Option, um Daten basierend auf einer vom Benutzer definierten Liste von Spalten zu unterteilen (obwohl Sie vorsichtig sein müssen, dass Sie immer eine Kopie des Datenrahmens verwenden und Inplace- Parameter nicht auf True gesetzt werden sollten !!).

Eine andere Option ist die Verwendung von pandas.columns.difference () , die einen festgelegten Unterschied für Spaltennamen bewirkt und einen Indextyp eines Arrays zurückgibt, der die gewünschten Spalten enthält. Folgendes ist die Lösung:

df = pd.DataFrame([[2,3,4],[3,4,5]],columns=['a','b','c'],index=[1,2])
columns_for_differencing = ['a']
df1 = df.copy()[df.columns.difference(columns_for_differencing)]
print(df1)

Die Ausgabe wäre: b c 1 3 4 2 4 5

Harshit
quelle
1
Die Kopie () ist nicht erforderlich. dh: df1 = df[df.columns.difference(columns_for_differencing)]gibt einen neuen / kopierten Datenrahmen zurück. Sie können df1Änderungen vornehmen, ohne Änderungen vorzunehmen df. Danke übrigens. Das war genau das, was ich brauchte.
Bazyli Debowski
4

Sie können auch df.pop () verwenden

>>> df = pd.DataFrame([('falcon', 'bird',    389.0),
...                    ('parrot', 'bird',     24.0),
...                    ('lion',   'mammal',   80.5),
...                    ('monkey', 'mammal', np.nan)],
...                   columns=('name', 'class', 'max_speed'))
>>> df
     name   class  max_speed
0  falcon    bird      389.0
1  parrot    bird       24.0
2    lion  mammal       80.5
3  monkey  mammal 

>>> df.pop('class')
0      bird
1      bird
2    mammal
3    mammal
Name: class, dtype: object

>>> df
     name  max_speed
0  falcon      389.0
1  parrot       24.0
2    lion       80.5
3  monkey        NaN

Lassen Sie mich wissen, wenn dies für Sie hilfreich ist. Verwenden Sie bitte df.pop (c).

Puneet Sinha
quelle
3

Ich habe mehrere Antworten darauf gesehen, aber mir blieb dies unklar. Wie würden Sie diese interessierenden Spalten auswählen? Die Antwort darauf lautet: Wenn Sie sie in einer Liste gesammelt haben, können Sie die Spalten einfach anhand der Liste referenzieren.

Beispiel

print(extracted_features.shape)
print(extracted_features)

(63,)
['f000004' 'f000005' 'f000006' 'f000014' 'f000039' 'f000040' 'f000043'
 'f000047' 'f000048' 'f000049' 'f000050' 'f000051' 'f000052' 'f000053'
 'f000054' 'f000055' 'f000056' 'f000057' 'f000058' 'f000059' 'f000060'
 'f000061' 'f000062' 'f000063' 'f000064' 'f000065' 'f000066' 'f000067'
 'f000068' 'f000069' 'f000070' 'f000071' 'f000072' 'f000073' 'f000074'
 'f000075' 'f000076' 'f000077' 'f000078' 'f000079' 'f000080' 'f000081'
 'f000082' 'f000083' 'f000084' 'f000085' 'f000086' 'f000087' 'f000088'
 'f000089' 'f000090' 'f000091' 'f000092' 'f000093' 'f000094' 'f000095'
 'f000096' 'f000097' 'f000098' 'f000099' 'f000100' 'f000101' 'f000103']

Ich habe das folgende Listen- / Numpy-Array extracted_featuresmit 63 Spalten. Der ursprüngliche Datensatz hat 103 Spalten, und ich möchte genau diese extrahieren, dann würde ich verwenden

dataset[extracted_features]

Und Sie werden damit enden

Geben Sie hier die Bildbeschreibung ein

Dies würden Sie häufig beim maschinellen Lernen verwenden (genauer gesagt bei der Auswahl von Funktionen). Ich würde gerne auch andere Möglichkeiten diskutieren, aber ich denke, dass dies bereits von anderen Stapelüberblumen abgedeckt wurde. Hoffe das war hilfreich!

Kareem Jeiroudi
quelle
2

Sie können die pandas.DataFrame.filterMethode verwenden, um Spalten wie folgt zu filtern oder neu anzuordnen:

df1 = df.filter(['a', 'b'])
Ramin Melikov
quelle
0
df[['a','b']] # select all rows of 'a' and 'b'column 
df.loc[0:10, ['a','b']] # index 0 to 10 select column 'a' and 'b'
df.loc[0:10, ['a':'b']] # index 0 to 10 select column 'a' to 'b'
df.iloc[0:10, 3:5] # index 0 to 10 and column 3 to 5
df.iloc[3, 3:5] # index 3 of column 3 to 5
Biplob Das
quelle