แพนด้า: วิธีที่ดีที่สุดในการเลือกคอลัมน์ทั้งหมดที่มีชื่อขึ้นต้นด้วย X


113

ฉันมี 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],})

ฉันต้องการที่จะเลือกค่าของ 1 foo.ในคอลัมน์ที่เริ่มต้นด้วย มีวิธีอื่นที่ดีกว่าไหมนอกจาก:

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]

คำตอบควรพิมพ์ DataFrame ดังนี้:

   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]

คำตอบ:


169

เพียงแค่ทำความเข้าใจรายการเพื่อสร้างคอลัมน์ของคุณ:

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

อีกวิธีหนึ่งคือการสร้างชุดจากคอลัมน์และใช้วิธี vectorised 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

แก้ไข

ตกลงหลังจากเห็นสิ่งที่คุณต้องการคำตอบที่ซับซ้อนคือ:

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

70

ตอนนี้ดัชนีของแพนด้ารองรับการทำงานของสตริงแล้ววิธีที่ง่ายที่สุดและดีที่สุดในการเลือกคอลัมน์ที่ขึ้นต้นด้วย 'foo' คือ:

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

ในการเลือกเฉพาะแถวที่ต้องการ (ประกอบด้วย a 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

นี่คือคำตอบที่ฉันมาที่นี่ซึ่งตรงกับชื่อคำถาม สิ่งที่ OP ต้องการจริงๆคือ "วิธีที่ดีที่สุดในการเลือกแถวที่มีตัวกรองตามคอลัมน์ที่ขึ้นต้นด้วย x"
scign

8

วิธีที่ง่ายที่สุดคือการใช้ str กับชื่อคอลัมน์โดยตรงไม่จำเป็นต้องใช้ pd.Series

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



2

จากคำตอบของ @ EdChum คุณสามารถลองวิธีแก้ไขปัญหาต่อไปนี้:

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

fooนี้จะเป็นประโยชน์มากในกรณีที่ไม่ได้ทั้งหมดคอลัมน์ที่คุณต้องการเลือกเริ่มต้นด้วย วิธีนี้จะเลือกคอลัมน์ทั้งหมดที่มีสตริงย่อยfooและสามารถวางไว้ที่จุดใดก็ได้ของชื่อคอลัมน์

ในสาระสำคัญฉันแทนที่.startswith()ด้วย.contains().


1

คุณสามารถลอง regex ที่นี่เพื่อกรองคอลัมน์ที่ขึ้นต้นด้วย "foo"

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

หากคุณต้องการมีสตริง foo ในคอลัมน์ของคุณแล้ว

df.filter(regex='foo*')

จะเหมาะสม

สำหรับขั้นตอนต่อไปคุณสามารถใช้

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

เพื่อกรองแถวที่หนึ่งในค่าของคอลัมน์ 'foo *' คือ 1


0

ทางออกของฉัน ประสิทธิภาพอาจช้าลง:

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

อีกทางเลือกหนึ่งสำหรับการเลือกรายการที่ต้องการคือการใช้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

หมายถึงแถวนั้น3และ4ไม่มี a 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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.