2014-12-03 98 views
29

所有列最佳方式我有一個數據幀:大熊貓:選擇開始X

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

我想在列選擇開始foo.值1。有沒有更好的辦法做到這一點以外:類似於編寫類似

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

東西:

df2= df[df.STARTS_WITH_FOO == 1] 

答案應該打印出這樣的數據幀:

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] 

回答

45

剛執行列表理解來創建您的列:

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 

另一種方法是創建一個從列系列和使用矢量化STR方法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 

爲了達到你想要什麼,你需要添加以下過濾不符合你的價值觀==1標準:

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 

編輯

OK看到你想要的東西后,令人費解的答案是這樣的:

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

請考慮您的選項2移動到頂部您的回答 – JanLauGe 2018-02-26 15:31:46

+0

downvoter謹慎解釋? – EdChum 2018-02-26 16:35:59

+0

@JanLauGe雖然'startswith'將是純粹的'pandas'方法,但使用列表理解實際上是最快的方法,所以我已經發布了兩種方法 – EdChum 2018-02-26 16:36:38

17

現在,大熊貓的索引支持字符串操作,可以說是最簡單和最好的方式選擇開頭列‘富’僅僅是:

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

或者,您也可以過濾柱(或行)標籤df.filter()。要指定一個正則表達式匹配的名稱與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 

只選擇所需的行(含1)和列,您可以使用loc,用filter選擇列(或任何其他方法)和行使用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 
+0

那麼選擇部分呢?其中df [cols] == 1被應用,我會做一個for循環或者有更快的方法嗎? – ccsv 2014-12-03 15:37:20

+0

@ccsv我想你可以直接寫'df.filter(regex = r'^ foo \。',axis = 1)== 1'(讓我知道我是否誤解了你想要的)。 – 2014-12-03 15:38:44

+0

它是關閉你只需要轉換布爾值並刪除一些行。如果你運行的代碼,我有它的所有列,但只有行0,1,2,5,因爲它們的值爲1的標題爲'foo' – ccsv 2014-12-03 15:49:12

1

我的解決方案。這可能是對性能較慢:

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 
1

所希望的項目的選擇另一種選擇是使用map

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

,讓你所有的列包含一個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 

行選

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

在@ ajcr的答案,讓你:

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

意味着該行34不包含1,不會被選中。

選擇列的使用布爾索引這樣做是:

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

在上面這個例子返回

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

所以,如果一列不以foo開始,返回False,因此未選擇該列。

如果你只想返回包含一個1所有行 - 如您所需的輸出暗示 - 你可以簡單地做

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

返回

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