Pandas: Der beste Weg, um alle Spalten auszuwählen, deren Namen mit X beginnen

102

Ich habe einen DataFrame:

import pandas as pd
import numpy as np

df = pd.DataFrame({'foo.aa': [1, 2.1, np.nan, 4.7, 5.6, 6.8],
                   'foo.fighters': [0, 1, np.nan, 0, 0, 0],
                   'foo.bars': [0, 0, 0, 0, 0, 1],
                   'bar.baz': [5, 5, 6, 5, 5.6, 6.8],
                   'foo.fox': [2, 4, 1, 0, 0, 5],
                   'nas.foo': ['NA', 0, 1, 0, 0, 0],
                   'foo.manchu': ['NA', 0, 0, 0, 0, 0],})

Ich möchte Werte von 1 in Spalten auswählen, die mit beginnen foo.. Gibt es einen besseren Weg, dies zu tun als:

df2 = df[(df['foo.aa'] == 1)|
(df['foo.fighters'] == 1)|
(df['foo.bars'] == 1)|
(df['foo.fox'] == 1)|
(df['foo.manchu'] == 1)
]

Ähnlich wie beim Schreiben von:

df2= df[df.STARTS_WITH_FOO == 1]

Die Antwort sollte einen DataFrame wie folgt ausdrucken:

   bar.baz  foo.aa  foo.bars  foo.fighters  foo.fox foo.manchu nas.foo
0      5.0     1.0         0             0        2         NA      NA
1      5.0     2.1         0             1        4          0       0
2      6.0     NaN         0           NaN        1          0       1
5      6.8     6.8         1             0        5          0       0

[4 rows x 7 columns]
ccsv
quelle

Antworten:

150

Führen Sie einfach ein Listenverständnis durch, um Ihre Spalten zu erstellen:

In [28]:

filter_col = [col for col in df if col.startswith('foo')]
filter_col
Out[28]:
['foo.aa', 'foo.bars', 'foo.fighters', 'foo.fox', 'foo.manchu']
In [29]:

df[filter_col]
Out[29]:
   foo.aa  foo.bars  foo.fighters  foo.fox foo.manchu
0     1.0         0             0        2         NA
1     2.1         0             1        4          0
2     NaN         0           NaN        1          0
3     4.7         0             0        0          0
4     5.6         0             0        0          0
5     6.8         1             0        5          0

Eine andere Methode besteht darin, eine Reihe aus den Spalten zu erstellen und die vektorisierte str-Methode zu verwenden startswith:

In [33]:

df[df.columns[pd.Series(df.columns).str.startswith('foo')]]
Out[33]:
   foo.aa  foo.bars  foo.fighters  foo.fox foo.manchu
0     1.0         0             0        2         NA
1     2.1         0             1        4          0
2     NaN         0           NaN        1          0
3     4.7         0             0        0          0
4     5.6         0             0        0          0
5     6.8         1             0        5          0

Um das zu erreichen, was Sie wollen, müssen Sie Folgendes hinzufügen, um die Werte zu filtern, die Ihren ==1Kriterien nicht entsprechen :

In [36]:

df[df[df.columns[pd.Series(df.columns).str.startswith('foo')]]==1]
Out[36]:
   bar.baz  foo.aa  foo.bars  foo.fighters  foo.fox foo.manchu nas.foo
0      NaN       1       NaN           NaN      NaN        NaN     NaN
1      NaN     NaN       NaN             1      NaN        NaN     NaN
2      NaN     NaN       NaN           NaN        1        NaN     NaN
3      NaN     NaN       NaN           NaN      NaN        NaN     NaN
4      NaN     NaN       NaN           NaN      NaN        NaN     NaN
5      NaN     NaN         1           NaN      NaN        NaN     NaN

BEARBEITEN

OK, nachdem Sie gesehen haben, was Sie wollen, lautet die verschlungene Antwort:

In [72]:

df.loc[df[df[df.columns[pd.Series(df.columns).str.startswith('foo')]] == 1].dropna(how='all', axis=0).index]
Out[72]:
   bar.baz  foo.aa  foo.bars  foo.fighters  foo.fox foo.manchu nas.foo
0      5.0     1.0         0             0        2         NA      NA
1      5.0     2.1         0             1        4          0       0
2      6.0     NaN         0           NaN        1          0       1
5      6.8     6.8         1             0        5          0       0
EdChum
quelle
63

Da die Pandas-Indizes Zeichenfolgenoperationen unterstützen, ist die wohl einfachste und beste Möglichkeit, Spalten auszuwählen, die mit 'foo' beginnen, nur noch:

df.loc[:, df.columns.str.startswith('foo')]

Alternativ können Sie Spalten- (oder Zeilen-) Beschriftungen mit filtern df.filter(). So geben Sie einen regulären Ausdruck an, der den Namen entspricht, die mit beginnen foo.:

>>> df.filter(regex=r'^foo\.', axis=1)
   foo.aa  foo.bars  foo.fighters  foo.fox foo.manchu
0     1.0         0             0        2         NA
1     2.1         0             1        4          0
2     NaN         0           NaN        1          0
3     4.7         0             0        0          0
4     5.6         0             0        0          0
5     6.8         1             0        5          0

Um nur die erforderlichen Zeilen (mit a 1) und die Spalten locauszuwählen , können Sie die Spalten mit filter(oder einer anderen Methode) und die Zeilen mit any:

>>> df.loc[(df == 1).any(axis=1), df.filter(regex=r'^foo\.', axis=1).columns]
   foo.aa  foo.bars  foo.fighters  foo.fox foo.manchu
0     1.0         0             0        2         NA
1     2.1         0             1        4          0
2     NaN         0           NaN        1          0
5     6.8         1             0        5          0
Alex Riley
quelle
7

Am einfachsten ist es, str direkt für Spaltennamen zu verwenden, ohne dass dies erforderlich ist pd.Series

df.loc[:,df.columns.str.startswith("foo")]

Mohammed Omar Elsiddieg
quelle
1

Basierend auf der Antwort von @ EdChum können Sie die folgende Lösung ausprobieren:

df[df.columns[pd.Series(df.columns).str.contains("foo")]]

Dies ist sehr hilfreich, wenn nicht alle Spalten, mit denen Sie auswählen möchten, beginnen foo. Diese Methode wählt alle Spalten aus, die den Teilstring enthalten, foound kann an einer beliebigen Stelle des Spaltennamens eingefügt werden.

Im Wesentlichen ersetzt ich .startswith()mit .contains().

Arturo Sbr
quelle
0

Meine Lösung. Die Leistung kann langsamer sein:

a = pd.concat(df[df[c] == 1] for c in df.columns if c.startswith('foo'))
a.sort_index()


   bar.baz  foo.aa  foo.bars  foo.fighters  foo.fox foo.manchu nas.foo
0      5.0     1.0         0             0        2         NA      NA
1      5.0     2.1         0             1        4          0       0
2      6.0     NaN         0           NaN        1          0       1
5      6.8     6.8         1             0        5          0       0
Robbie Liu
quelle
0

Eine weitere Option für die Auswahl der gewünschten Einträge ist map:

df.loc[(df == 1).any(axis=1), df.columns.map(lambda x: x.startswith('foo'))]

Hier finden Sie alle Spalten für Zeilen, die Folgendes enthalten 1:

   foo.aa  foo.bars  foo.fighters  foo.fox foo.manchu
0     1.0         0             0        2         NA
1     2.1         0             1        4          0
2     NaN         0           NaN        1          0
5     6.8         1             0        5          0

Die Zeilenauswahl erfolgt durch

(df == 1).any(axis=1)

wie in der Antwort von @ ajcr, die Ihnen gibt:

0     True
1     True
2     True
3    False
4    False
5     True
dtype: bool

Dies bedeutet, dass Zeile 3und 4kein a enthalten 1und nicht ausgewählt werden.

Die Auswahl der Spalten erfolgt mithilfe der Booleschen Indizierung wie folgt:

df.columns.map(lambda x: x.startswith('foo'))

Im obigen Beispiel wird dies zurückgegeben

array([False,  True,  True,  True,  True,  True, False], dtype=bool)

Wenn also eine Spalte nicht mit beginnt foo, Falsewird sie zurückgegeben und die Spalte wird daher nicht ausgewählt.

Wenn Sie nur alle Zeilen zurückgeben möchten, die ein enthalten 1- wie in Ihrer gewünschten Ausgabe angegeben -, können Sie dies einfach tun

df.loc[(df == 1).any(axis=1)]

was zurückkehrt

   bar.baz  foo.aa  foo.bars  foo.fighters  foo.fox foo.manchu nas.foo
0      5.0     1.0         0             0        2         NA      NA
1      5.0     2.1         0             1        4          0       0
2      6.0     NaN         0           NaN        1          0       1
5      6.8     6.8         1             0        5          0       0
Cleb
quelle
0

Sie können hier den regulären Ausdruck versuchen, um die Spalten herauszufiltern, die mit "foo" beginnen.

df.filter(regex='^foo*')

Wenn Sie den String foo in Ihrer Spalte haben müssen, dann

df.filter(regex='foo*')

wäre angemessen.

Für den nächsten Schritt können Sie verwenden

df[df.filter(regex='^foo*').values==1]

um die Zeilen herauszufiltern, in denen einer der Werte der Spalte 'foo *' 1 ist.

Ricky
quelle