pandas: cara terbaik untuk memilih semua kolom yang namanya dimulai dengan X

106

Saya memiliki 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],})

Saya ingin memilih nilai 1 di kolom yang dimulai dengan foo.. Apakah ada cara yang lebih baik untuk melakukannya selain:

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

Sesuatu yang mirip dengan menulis sesuatu seperti:

df2= df[df.STARTS_WITH_FOO == 1]

Jawabannya harus mencetak DataFrame seperti ini:

   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
sumber

Jawaban:

155

Cukup lakukan pemahaman daftar untuk membuat kolom Anda:

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

Metode lain adalah membuat rangkaian dari kolom dan menggunakan metode str vektor 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

Untuk mencapai apa yang Anda inginkan, Anda perlu menambahkan yang berikut ini untuk memfilter nilai yang tidak memenuhi ==1kriteria Anda :

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 setelah melihat apa yang Anda inginkan, jawaban yang berbelit-belit adalah ini:

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
sumber
66

Sekarang indeks panda mendukung operasi string, bisa dibilang cara termudah dan terbaik untuk memilih kolom yang dimulai dengan 'foo' adalah:

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

Alternatifnya, Anda bisa memfilter label kolom (atau baris) dengan df.filter(). Untuk menentukan ekspresi reguler agar cocok dengan nama yang diawali dengan 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

Untuk memilih hanya baris yang diperlukan (berisi a 1) dan kolom, Anda dapat menggunakan loc, memilih kolom menggunakan filter(atau metode lain) dan baris menggunakan 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
sumber
Ini adalah jawaban saya datang ke sini, yang cocok dengan judul pertanyaan. Apa yang sebenarnya diinginkan OP lebih seperti "Cara terbaik untuk memilih baris dengan filter hanya berdasarkan pada kolom yang dimulai dengan x".
scign
7

Cara termudah adalah dengan menggunakan str langsung pada nama kolom, tidak perlu pd.Series

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

Mohammed Omar Elsiddieg
sumber
1

Berdasarkan jawaban @ EdChum, Anda dapat mencoba solusi berikut:

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

Ini akan sangat membantu jika tidak semua kolom yang ingin Anda pilih dimulai foo. Metode ini memilih semua kolom yang berisi substring foodan dapat ditempatkan di titik mana pun dari nama kolom.

Intinya, saya ganti .startswith()dengan .contains().

Arturo Sbr
sumber
0

Solusi saya. Mungkin lebih lambat pada kinerja:

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
sumber
0

Pilihan lain untuk pemilihan entri yang diinginkan adalah dengan menggunakan map:

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

yang memberi Anda semua kolom untuk baris yang berisi 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

Pemilihan baris dilakukan oleh

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

seperti dalam jawaban @ ajcr yang memberi Anda:

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

artinya baris tersebut 3dan 4tidak mengandung a 1dan tidak akan dipilih.

The pemilihan kolom dilakukan dengan menggunakan pengindeksan Boolean seperti ini:

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

Dalam contoh di atas, ini mengembalikan

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

Jadi, jika kolom tidak dimulai dengan foo, Falsedikembalikan dan karena itu kolom tidak dipilih.

Jika Anda hanya ingin mengembalikan semua baris yang berisi 1- seperti yang disarankan keluaran yang Anda inginkan - Anda dapat melakukannya

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

yang kembali

   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
sumber
0

Anda dapat mencoba regex di sini untuk memfilter kolom yang dimulai dengan "foo"

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

Jika Anda perlu memiliki string foo di kolom Anda, maka

df.filter(regex='foo*')

akan sesuai.

Untuk langkah selanjutnya, Anda bisa menggunakan

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

untuk menyaring baris yang salah satu nilai kolom 'foo *' adalah 1.

Ricky
sumber
0

Dalam kasus saya, saya membutuhkan daftar prefiks

colsToScale=["production", "test", "development"]
dc[dc.columns[dc.columns.str.startswith(tuple(colsToScale))]]
Flavio Sousa
sumber