วางคอลัมน์ที่มีชื่อประกอบด้วยสตริงเฉพาะจากแพนด้า DataFrame


112

ฉันมีดาต้าเฟรมแพนด้าที่มีชื่อคอลัมน์ต่อไปนี้:

Result1, Test1, Result2, Test2, Result3, Test3 ฯลฯ ...

ฉันต้องการปล่อยคอลัมน์ทั้งหมดที่มีชื่อคำว่า "Test" ตัวเลขของคอลัมน์ดังกล่าวไม่คงที่ แต่ขึ้นอยู่กับฟังก์ชันก่อนหน้า

ฉันจะทำเช่นนั้นได้อย่างไร?

คำตอบ:


77
import pandas as pd

import numpy as np

array=np.random.random((2,4))

df=pd.DataFrame(array, columns=('Test1', 'toto', 'test2', 'riri'))

print df

      Test1      toto     test2      riri
0  0.923249  0.572528  0.845464  0.144891
1  0.020438  0.332540  0.144455  0.741412

cols = [c for c in df.columns if c.lower()[:4] != 'test']

df=df[cols]

print df
       toto      riri
0  0.572528  0.144891
1  0.332540  0.741412

2
OP ไม่ได้ระบุว่าการลบควรไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่
Phillip Cloud

176

นี่คือวิธีหนึ่งในการดำเนินการนี้:

df = df[df.columns.drop(list(df.filter(regex='Test')))]

49
หรือเข้าที่โดยตรง:df.drop(list(df.filter(regex = 'Test')), axis = 1, inplace = True)
Axel

7
นี่เป็นวิธีการแก้ปัญหาที่หรูหรากว่าคำตอบที่ยอมรับ ฉันจะแยกมันออกมาอีกเล็กน้อยเพื่อแสดงว่าเหตุใดโดยหลักแล้วการดึงข้อมูลlist(df.filter(regex='Test'))เพื่อแสดงให้เห็นว่าไลน์กำลังทำอะไร ฉันจะเลือกใช้df.filter(regex='Test').columnsการแปลงรายการ
Charles

3
วิธีนี้เป็นวิธีที่สง่างามกว่าคำตอบที่ยอมรับ
deepelement

4
ฉันสงสัยจริงๆว่าความคิดเห็นที่บอกว่าคำตอบนี้ "สง่างาม" หมายความว่าอย่างไร ตัวฉันเองพบว่ามันค่อนข้างสับสนเมื่อควรอ่านรหัส python ก่อน นอกจากนี้ยังช้ากว่าคำตอบแรกถึงสองเท่า และจะใช้regexคีย์เวิร์ดเมื่อlikeคีย์เวิร์ดน่าจะเพียงพอมากขึ้น
Jacquot

2
นี่ไม่ใช่คำตอบที่ดีอย่างที่ผู้คนกล่าวอ้าง ปัญหาfilterคือจะส่งคืนสำเนาของข้อมูลทั้งหมดเป็นคอลัมน์ที่คุณต้องการทิ้ง จะเป็นการสิ้นเปลืองหากคุณเพียงส่งผลลัพธ์นี้ไปยังdrop(ซึ่งส่งคืนสำเนาอีกครั้ง) ... ทางออกที่ดีกว่าคือstr.startswith(ฉันได้เพิ่มคำตอบไว้ที่นี่แล้ว)
cs95

45

ถูกกว่าเร็วกว่าและสำนวน: str.contains

ในเวอร์ชันล่าสุดของแพนด้าคุณสามารถใช้วิธีการสตริงในดัชนีและคอลัมน์ ที่นี่str.startswithดูเหมือนจะเป็นแบบที่ดี

ในการลบคอลัมน์ทั้งหมดที่เริ่มต้นด้วยสตริงย่อยที่กำหนด:

df.columns.str.startswith('Test')
# array([ True, False, False, False])

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

  toto test2 riri
0    x     x    x
1    x     x    x

สำหรับการจับคู่แบบไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่คุณสามารถใช้การจับคู่แบบ regex str.containsกับ SOL anchor:

df.columns.str.contains('^test', case=False)
# array([ True, False,  True, False])

df.loc[:,~df.columns.str.contains('^test', case=False)] 

  toto riri
0    x    x
1    x    x

หากมีความเป็นไปได้แบบผสมให้ระบุna=Falseด้วย


15

คุณสามารถกรองคอลัมน์ที่คุณต้องการโดยใช้ "ตัวกรอง"

import pandas as pd
import numpy as np

data2 = [{'test2': 1, 'result1': 2}, {'test': 5, 'result34': 10, 'c': 20}]

df = pd.DataFrame(data2)

df

    c   result1     result34    test    test2
0   NaN     2.0     NaN     NaN     1.0
1   20.0    NaN     10.0    5.0     NaN

ตอนนี้กรอง

df.filter(like='result',axis=1)

ขอรับ ..

   result1  result34
0   2.0     NaN
1   NaN     10.0

4
ตอบดีที่สุด! ขอบคุณ. กรองตรงข้ามกันยังไง? not like='result'
StallingOne

2
จากนั้นทำสิ่งนี้: df = df.drop (df.filter (like = 'result', axis = 1) .columns, axis = 1)
Amir

14

สามารถทำได้อย่างเรียบร้อยในบรรทัดเดียวด้วย:

df = df.drop(df.filter(regex='Test').columns, axis=1)

1
ในทำนองเดียวกัน (และเร็วกว่า):df.drop(df.filter(regex='Test').columns, axis=1, inplace=True)
Max Ghenis

9

ใช้DataFrame.selectวิธีการ:

In [38]: df = DataFrame({'Test1': randn(10), 'Test2': randn(10), 'awesome': randn(10)})

In [39]: df.select(lambda x: not re.search('Test\d+', x), axis=1)
Out[39]:
   awesome
0    1.215
1    1.247
2    0.142
3    0.169
4    0.137
5   -0.971
6    0.736
7    0.214
8    0.111
9   -0.214

และสหกรณ์ไม่ได้ระบุว่าเป็นจำนวนที่จะต้องปฏิบัติตาม 'ทดสอบ': ฉันต้องการที่จะลดลงคอลัมน์ทั้งหมดที่มีชื่อมีคำว่า "ทดสอบ"
7

สมมติฐานที่ว่าตัวเลขตามการทดสอบมีความสมเหตุสมผลอย่างสมบูรณ์ อ่านคำถามอีกครั้ง
Phillip Cloud

2
ตอนนี้เห็น:FutureWarning: 'select' is deprecated and will be removed in a future release. You can use .loc[labels.map(crit)] as a replacement
flutefreak7

จำไว้import reก่อน
ijoseph

5

วิธีนี้ทำให้ทุกอย่างเข้าที่ คำตอบอื่น ๆ จำนวนมากสร้างสำเนาและไม่มีประสิทธิภาพเท่า:

df.drop(df.columns[df.columns.str.contains('Test')], axis=1, inplace=True)



1

วิธีที่สั้นที่สุดคือ:

resdf = df.filter(like='Test',axis=1)

นี้ถูกปกคลุมไปแล้วโดยคำตอบนี้
Gino Mempin

1
แม้ว่าคำตอบที่เชื่อมโยงในความคิดเห็นด้านบนจะคล้ายกัน แต่ก็ไม่เหมือนกัน ในความเป็นจริงมันเกือบจะตรงกันข้าม
Makyen

1

คำถามระบุว่า 'ฉันต้องการทิ้งคอลัมน์ทั้งหมดที่มีชื่อคำว่า "Test" "

test_columns = [col for col in df if 'Test' in col]
df.drop(columns=test_columns, inplace=True)

0

วิธีแก้ปัญหาเมื่อวางรายการชื่อคอลัมน์ที่มี regex ฉันชอบแนวทางนี้เพราะฉันแก้ไขรายการแบบหล่นบ่อยครั้ง ใช้ regex ตัวกรองเชิงลบสำหรับรายการแบบหล่น

drop_column_names = ['A','B.+','C.*']
drop_columns_regex = '^(?!(?:'+'|'.join(drop_column_names)+')$)'
print('Dropping columns:',', '.join([c for c in df.columns if re.search(drop_columns_regex,c)]))
df = df.filter(regex=drop_columns_regex,axis=1)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.