it-swarm.com.de

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

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 foo. Beginnen. Gibt es eine bessere Möglichkeit 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 ausgeben:

   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]
67
ccsv

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 möchten, müssen Sie Folgendes hinzufügen, um die Werte zu filtern, die Ihren ==1 - Kriterien 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

[~ # ~] edit [~ # ~]

OK, nachdem Sie gesehen haben, was Sie wollen, lautet die gewundene Antwort wie folgt:

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
101
EdChum

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

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

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

>>> 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 einem 1) Und die Spalten auszuwählen, können Sie loc verwenden und die Spalten mit filter (oder einer anderen Methode) und die Zeilen mit auswählen 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
41
Alex Riley

Eine weitere Möglichkeit zur Auswahl der gewünschten Einträge ist die Verwendung von map:

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

das gibt Ihnen alle Spalten für Zeilen, die einen 1 enthalten:

   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

Das Zeilenauswahl erfolgt durch

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

wie in @ Ajcrs Antwort, die Ihnen gibt:

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

dies bedeutet, dass die Zeilen 3 und 4 kein 1 enthalten und nicht ausgewählt werden.

Das Auswahl der Spalten wird mit Boolescher Indizierung wie folgt durchgeführt:

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)

Beginnt eine Spalte also nicht mit foo, wird False zurückgegeben und die Spalte daher nicht ausgewählt.

Wenn Sie nur alle Zeilen mit einem 1 Zurückgeben möchten, können Sie dies ganz 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
0
Cleb

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
0
Robbie Liu