จะทดสอบได้อย่างไรว่าสตริงมีสตริงย่อยในรายการเป็นแพนด้าหรือไม่?


119

มีฟังก์ชันใดบ้างที่จะเทียบเท่ากับการรวมกันของdf.isin()และdf[col].str.contains()?

ตัวอย่างเช่นพูดว่าฉันมีซีรีส์ s = pd.Series(['cat','hat','dog','fog','pet'])และฉันต้องการค้นหาสถานที่ทั้งหมดที่sมีทั้งหมด['og', 'at']ฉันอยากได้ทุกอย่างยกเว้น 'สัตว์เลี้ยง'

ฉันมีวิธีแก้ปัญหา แต่มันค่อนข้างไม่ดี:

searchfor = ['og', 'at']
found = [s.str.contains(x) for x in searchfor]
result = pd.DataFrame[found]
result.any()

มีวิธีที่ดีกว่านี้หรือไม่?


หมายเหตุ : มีวิธีการแก้ปัญหาคือการอธิบายโดย @unutbupd.Series.str.containsซึ่งมีประสิทธิภาพมากกว่าการใช้ หากประสิทธิภาพเป็นปัญหาอาจเป็นเรื่องที่ควรค่าแก่การตรวจสอบ
jpp

ขอแนะนำให้ตรวจสอบคำตอบนี้สำหรับการค้นหาสตริงบางส่วนโดยใช้คีย์เวิร์ด / regexes หลายคำ (เลื่อนลงไปที่หัวข้อย่อย" Multiple Substring Search ")
cs95

คำตอบ:


219

ทางเลือกหนึ่งคือใช้|อักขระregex เพื่อพยายามจับคู่สตริงย่อยแต่ละรายการในคำในซีรี่ส์ของคุณs(ยังคงใช้อยู่str.contains)

คุณสามารถสร้าง regex โดยการเข้าร่วมคำในsearchforกับ|:

>>> searchfor = ['og', 'at']
>>> s[s.str.contains('|'.join(searchfor))]
0    cat
1    hat
2    dog
3    fog
dtype: object

ดังที่ @AndyHayden ระบุไว้ในความคิดเห็นด้านล่างให้ดูแลว่าสตริงย่อยของคุณมีอักขระพิเศษเช่น$และ^ที่คุณต้องการจับคู่ตามตัวอักษรหรือไม่ อักขระเหล่านี้มีความหมายเฉพาะในบริบทของนิพจน์ทั่วไปและจะส่งผลต่อการจับคู่

คุณสามารถทำให้รายการสตริงย่อยของคุณปลอดภัยยิ่งขึ้นโดยการหลีกเลี่ยงอักขระที่ไม่ใช่ตัวเลขและตัวอักษรด้วยre.escape:

>>> import re
>>> matches = ['$money', 'x^y']
>>> safe_matches = [re.escape(m) for m in matches]
>>> safe_matches
['\\$money', 'x\\^y']

str.containsสตริงที่มีในรายการใหม่นี้จะตรงกับตัวละครแต่ละตัวอักษรเมื่อใช้กับ


4
อาจจะดีที่จะเพิ่มลิงค์นี้pandas.pydata.org/pandas-docs/stable/…ด้วย เริ่มจากแพนด้า 0.15 การใช้งานสตริงจะง่ายยิ่งขึ้น
goofd

6
สิ่งหนึ่งที่คุณต้องดูแลคือถ้าสตริงในการค้นหามีอักขระ regex พิเศษ (คุณสามารถแมปกับ re.escape )
Andy Hayden

@AndyHayden ขอบคุณฉันได้ปรับปรุงคำตอบของฉันเพื่อพิจารณาภาวะแทรกซ้อนนี้
Alex Riley

ฉันไม่รู้ว่าทำไมวิธีของคุณใช้ไม่ได้กับ "str.startswith ('|' .join (searchfor))"
ดูฮยอนชิน

48

คุณสามารถใช้str.containsเพียงอย่างเดียวกับรูปแบบนิพจน์ทั่วไปโดยใช้OR (|):

s[s.str.contains('og|at')]

หรือคุณสามารถเพิ่มซีรีส์เพื่อdataframeใช้str.contains:

df = pd.DataFrame(s)
df[s.str.contains('og|at')] 

เอาท์พุท:

0 cat
1 hat
2 dog
3 fog 

ทำอย่างไรสำหรับ AND?
JacoSolari

1
@JacoSolari ลองดูคำตอบนี้stackoverflow.com/questions/37011734/…
เจมส์

1
@ เจมส์ใช่ขอบคุณ สำหรับการทำให้เสร็จสมบูรณ์นี่คือตัวเลือกที่ได้รับการโหวตมากที่สุดในคำตอบนั้น df.col.str.contains(r'(?=.*apple)(?=.*banana)',regex=True)
JacoSolari

1

นี่คือแลมด้าบรรทัดเดียวที่ใช้งานได้:

df["TrueFalse"] = df['col1'].apply(lambda x: 1 if any(i in x for i in searchfor) else 0)

การป้อนข้อมูล:

searchfor = ['og', 'at']

df = pd.DataFrame([('cat', 1000.0), ('hat', 2000000.0), ('dog', 1000.0), ('fog', 330000.0),('pet', 330000.0)], columns=['col1', 'col2'])

   col1  col2
0   cat 1000.0
1   hat 2000000.0
2   dog 1000.0
3   fog 330000.0
4   pet 330000.0

ใช้ Lambda:

df["TrueFalse"] = df['col1'].apply(lambda x: 1 if any(i in x for i in searchfor) else 0)

เอาท์พุท:

    col1    col2        TrueFalse
0   cat     1000.0      1
1   hat     2000000.0   1
2   dog     1000.0      1
3   fog     330000.0    1
4   pet     330000.0    0
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.