আমি কীভাবে কোনও পান্ডাস ডেটা ফ্রেম থেকে আংশিক স্ট্রিং দ্বারা নির্বাচন করব?
এই পোস্টটি পাঠকদের জন্য যা বোঝাতে চাইছে
- স্ট্রিং কলামে একটি স্ট্রিংয়ের সন্ধান করুন (সবচেয়ে সহজ কেস)
- একাধিক সাবস্ট্রিং অনুসন্ধান (অনুরূপ
isin
)
- পাঠ্য থেকে একটি সম্পূর্ণ শব্দ মেলে (যেমন, "নীল" "আকাশ নীল" তবে "নীলজয়" নয়)
- একাধিক পুরো শব্দ মেলে
- "ValueError: NA / NAN মানযুক্ত ভেক্টরের সাথে সূচী তৈরি করতে পারে না" এর পিছনের কারণটি বুঝুন "
... এবং অন্যদের তুলনায় কোন পদ্ধতিগুলি পছন্দ করা উচিত সে সম্পর্কে আরও জানতে চাই।
(পিএস: আমি অনুরূপ বিষয়ে প্রচুর প্রশ্ন দেখেছি, আমি ভেবেছিলাম এটি এখানে রেখে দেওয়া ভাল হবে))
বেসিক সাবস্ট্রিং অনুসন্ধান
# setup
df1 = pd.DataFrame({'col': ['foo', 'foobar', 'bar', 'baz']})
df1
col
0 foo
1 foobar
2 bar
3 baz
str.contains
সাবস্ট্রিং অনুসন্ধান বা রেজেক্স ভিত্তিক অনুসন্ধানের জন্য ব্যবহার করা যেতে পারে। আপনি স্পষ্টভাবে এটি অক্ষম না করা পর্যন্ত অনুসন্ধানটি রেজেক্স-ভিত্তিক ডিফল্ট হয়।
এখানে রেইগেক্স-ভিত্তিক অনুসন্ধানের উদাহরণ,
# find rows in `df1` which contain "foo" followed by something
df1[df1['col'].str.contains(r'foo(?!$)')]
col
1 foobar
কখনও কখনও রেজেক্স অনুসন্ধানের প্রয়োজন হয় না, তাই regex=False
এটি অক্ষম করার জন্য নির্দিষ্ট করুন ।
#select all rows containing "foo"
df1[df1['col'].str.contains('foo', regex=False)]
# same as df1[df1['col'].str.contains('foo')] but faster.
col
0 foo
1 foobar
পারফরম্যান্স অনুসারে, রেজেক্স অনুসন্ধান সাবস্ট্রিং অনুসন্ধানের চেয়ে ধীরে ধীরে:
df2 = pd.concat([df1] * 1000, ignore_index=True)
%timeit df2[df2['col'].str.contains('foo')]
%timeit df2[df2['col'].str.contains('foo', regex=False)]
6.31 ms ± 126 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.8 ms ± 241 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
আপনার যদি প্রয়োজন না হয় তবে রেজেক্স ভিত্তিক অনুসন্ধান ব্যবহার করা এড়িয়ে চলুন।
অ্যাড্রেসিং ValueError
গুলি
, কখনও কখনও একটি সাবস্ট্রিং অনুসন্ধান সম্পাদন এবং ফলাফলে ফিল্টারিং পরিণাম ডেকে আনবে
ValueError: cannot index with vector containing NA / NaN values
এটি সাধারণত আপনার অবজেক্ট কলামে মিশ্রিত ডেটা বা NaN এর কারণে হয়,
s = pd.Series(['foo', 'foobar', np.nan, 'bar', 'baz', 123])
s.str.contains('foo|bar')
0 True
1 True
2 NaN
3 True
4 False
5 NaN
dtype: object
s[s.str.contains('foo|bar')]
# ---------------------------------------------------------------------------
# ValueError Traceback (most recent call last)
স্ট্রিং নয় এমন যে কোনও কিছুতে স্ট্রিং পদ্ধতি প্রয়োগ করা যাবে না, ফলে ফলাফলটি NaN হয় (প্রাকৃতিকভাবে)। এই ক্ষেত্রে, na=False
নন-স্ট্রিং ডেটা উপেক্ষা করতে নির্দিষ্ট করুন,
s.str.contains('foo|bar', na=False)
0 True
1 True
2 False
3 True
4 False
5 False
dtype: bool
একাধিক সাবস্ট্রিং অনুসন্ধান
এটি সবচেয়ে সহজেই রেজেক্স ওআর পাইপ ব্যবহার করে একটি রেজেেক্স অনুসন্ধানের মাধ্যমে অর্জন করা যায়।
# Slightly modified example.
df4 = pd.DataFrame({'col': ['foo abc', 'foobar xyz', 'bar32', 'baz 45']})
df4
col
0 foo abc
1 foobar xyz
2 bar32
3 baz 45
df4[df4['col'].str.contains(r'foo|baz')]
col
0 foo abc
1 foobar xyz
3 baz 45
আপনি পদগুলির একটি তালিকাও তৈরি করতে পারেন, তারপরে এগুলিতে যোগদান করুন:
terms = ['foo', 'baz']
df4[df4['col'].str.contains('|'.join(terms))]
col
0 foo abc
1 foobar xyz
3 baz 45
কখনও কখনও, আপনার শর্তাদি রেজিেক্স মেটাচার্যাক্টর হিসাবে ব্যাখ্যা করা যেতে পারে এমন অক্ষর থাকলে সেগুলি এড়াতে বুদ্ধিমানের কাজ । যদি আপনার পদগুলিতে নিম্নলিখিত বর্ণগুলির একটি থাকে ...
. ^ $ * + ? { } [ ] \ | ( )
তারপরে, এগুলি re.escape
থেকে বাঁচতে আপনার প্রয়োজন হবে :
import re
df4[df4['col'].str.contains('|'.join(map(re.escape, terms)))]
col
0 foo abc
1 foobar xyz
3 baz 45
re.escape
বিশেষ অক্ষরগুলি থেকে পালিয়ে যাওয়ার প্রভাব রয়েছে যাতে তারা আক্ষরিক আচরণ করা হয়।
re.escape(r'.foo^')
# '\\.foo\\^'
সম্পূর্ণ শব্দ (গুলি) এর সাথে মিলছে
ডিফল্টরূপে, স্ট্রিং অনুসন্ধানটি পুরো শব্দ কিনা তা নির্বিশেষে নির্দিষ্ট সাবস্ট্রিং / প্যাটার্ন অনুসন্ধান করে। কেবলমাত্র পূর্ণ শব্দের সাথে মেলে, আমাদের এখানে নিয়মিত প্রকাশের প্রয়োজন হবে particular বিশেষত, আমাদের প্যাটার্নটি শব্দের গণ্ডি নির্দিষ্ট করতে হবে ( \b
)।
উদাহরণ স্বরূপ,
df3 = pd.DataFrame({'col': ['the sky is blue', 'bluejay by the window']})
df3
col
0 the sky is blue
1 bluejay by the window
এখন বিবেচনা করুন,
df3[df3['col'].str.contains('blue')]
col
0 the sky is blue
1 bluejay by the window
বনাম / সেকেন্ড
df3[df3['col'].str.contains(r'\bblue\b')]
col
0 the sky is blue
একাধিক পুরো শব্দ অনুসন্ধান
উপরের মত, আমরা যুক্ত \b
প্যাটার্নে একটি শব্দ সীমানা ( ) যুক্ত না করেই।
p = r'\b(?:{})\b'.format('|'.join(map(re.escape, terms)))
df4[df4['col'].str.contains(p)]
col
0 foo abc
3 baz 45
যেখানে p
দেখতে এইরকম দেখাচ্ছে,
p
# '\\b(?:foo|baz)\\b'
একটি দুর্দান্ত বিকল্প: তালিকা বিবেচনা ব্যবহার করুন !
কারন তুমি পারো! এবং আপনার উচিত! এগুলি সাধারণত স্ট্রিং পদ্ধতির তুলনায় কিছুটা দ্রুত হয় কারণ স্ট্রিং পদ্ধতিগুলি ভেক্টরাইজ করা শক্ত এবং সাধারণত লুপী বাস্তবায়ন থাকে।
পরিবর্তে,
df1[df1['col'].str.contains('foo', regex=False)]
in
একটি তালিকা কমপের অভ্যন্তরে অপারেটরটি ব্যবহার করুন ,
df1[['foo' in x for x in df1['col']]]
col
0 foo abc
1 foobar
পরিবর্তে,
regex_pattern = r'foo(?!$)'
df1[df1['col'].str.contains(regex_pattern)]
একটি তালিকা কমপ্লেক্সের অভ্যন্তরে re.compile
(আপনার রেজেক্সকে ক্যাশে রাখতে) ব্যবহার করুন Pattern.search
,
p = re.compile(regex_pattern, flags=re.IGNORECASE)
df1[[bool(p.search(x)) for x in df1['col']]]
col
1 foobar
"কল" এর যদি NaN থাকে তবে তার পরিবর্তে
df1[df1['col'].str.contains(regex_pattern, na=False)]
ব্যবহার,
def try_search(p, x):
try:
return bool(p.search(x))
except TypeError:
return False
p = re.compile(regex_pattern)
df1[[try_search(p, x) for x in df1['col']]]
col
1 foobar
str.contains
বোধগম্য তালিকা এবং তালিকাভুক্ত করা ছাড়াও , আপনি নিম্নলিখিত বিকল্পগুলিও ব্যবহার করতে পারেন।
np.char.find
সাবস্ট্রিং অনুসন্ধানগুলিকে সমর্থন করে (পড়ুন: কোনও রেজেক্স নয়)।
df4[np.char.find(df4['col'].values.astype(str), 'foo') > -1]
col
0 foo abc
1 foobar xyz
np.vectorize
এটি একটি লুপের চারপাশে একটি মোড়ক, তবে বেশিরভাগ পান্ডাস str
পদ্ধতির চেয়ে ওভারহেড কম ।
f = np.vectorize(lambda haystack, needle: needle in haystack)
f(df1['col'], 'foo')
# array([ True, True, False, False])
df1[f(df1['col'], 'foo')]
col
0 foo abc
1 foobar
রিজেক্স সমাধানগুলি সম্ভব:
regex_pattern = r'foo(?!$)'
p = re.compile(regex_pattern)
f = np.vectorize(lambda x: pd.notna(x) and bool(p.search(x)))
df1[f(df1['col'])]
col
1 foobar
DataFrame.query
পাইথন ইঞ্জিনের মাধ্যমে স্ট্রিং পদ্ধতি সমর্থন করে। এটি কোনও দৃশ্যমান পারফরম্যান্স বেনিফিট সরবরাহ করে না, তবে আপনার কীভাবে আপনার প্রশ্নগুলি গতিশীলভাবে উত্পন্ন করতে হবে তা জানতে এটি দরকারী useful
df1.query('col.str.contains("foo")', engine='python')
col
0 foo
1 foobar
পদ্ধতির পরিবার query
ও eval
পরিবার সম্পর্কে আরও তথ্য পিডি.এভাল () ব্যবহার করে পান্ডায় ডায়নামিক এক্সপ্রেশন মূল্যায়ন পাওয়া যায় ।
প্রস্তাবিত ব্যবহারের অগ্রাধিকার
- (প্রথম)
str.contains
, সরলতার জন্য এবং NaNs এবং মিশ্রিত ডেটা হ্যান্ডল করার জন্য
- এর কার্য সম্পাদনের জন্য বোধগম্যগুলি তালিকাবদ্ধ করুন (বিশেষত যদি আপনার ডেটা খাঁটি স্ট্রিং হয়)
np.vectorize
- (শেষ)
df.query