একটি পান্ডাস ডেটা ফ্রেম থেকে আংশিক স্ট্রিং দ্বারা নির্বাচন করুন


448

আমার কাছে DataFrame4 টি কলাম রয়েছে যার 2 টিতে স্ট্রিংয়ের মান রয়েছে। আমি ভাবছিলাম যে কোনও নির্দিষ্ট কলামের সাথে আংশিক স্ট্রিং ম্যাচের ভিত্তিতে সারিগুলি নির্বাচন করার কোনও উপায় ছিল কিনা?

অন্য কথায়, একটি ফাংশন বা ল্যাম্বদা ফাংশন যা এর মতো কিছু করে

re.search(pattern, cell_in_question) 

একটি বুলিয়ান ফিরে। আমি সিনট্যাক্স সাথে পরিচিত নই df[df['A'] == "hello world"]কিন্তু একটি আংশিক স্ট্রিং ম্যাচ বলে একইভাবে কাজ করার একটি উপায় খুঁজে মনে করতে পারে না 'hello'

কেউ আমাকে সঠিক দিকে নির্দেশ করতে সক্ষম হবে?

উত্তর:


786

গিথুব ইস্যু # 620 এর উপর ভিত্তি করে দেখে মনে হচ্ছে আপনি শীঘ্রই নিম্নলিখিতগুলি করতে সক্ষম হবেন:

df[df['A'].str.contains("hello")]

আপডেট: ভেক্টরাইজড স্ট্রিং পদ্ধতিগুলি (অর্থাত্ সিরিজ.স্টার) প্যান্ডাসে 0.8.1 এবং তার বেশি পাওয়া যায়।


1
আমি "হ্যালো" এবং "ব্রিটেন" সম্পর্কে কীভাবে যাব যদি আমি তাদের "ওআর" শর্তে সন্ধান করতে চাই।
লোনলিসোল

56
যেহেতু str। * পদ্ধতিগুলি ইনপুট প্যাটার্নটিকে একটি নিয়মিত প্রকাশ হিসাবে বিবেচনা করে, আপনি ব্যবহার করতে পারেনdf[df['A'].str.contains("Hello|Britain")]
গ্যারেট

7
এপিআই.str.contains ব্যবহার করে রূপান্তর করা কি সম্ভব ? .query()
zyxue


3
df[df['value'].astype(str).str.contains('1234.+')]নন-স্ট্রিং-টাইপ কলামগুলি ফিল্টার করার জন্য।
ফ্রান্সোইস লেব্ল্যাঙ্ক

213

আমি উপরে প্রস্তাবিত সমাধান চেষ্টা করেছিলাম:

df[df["A"].str.contains("Hello|Britain")]

এবং একটি ত্রুটি পেয়েছে:

ValueError: NA / NAN মানযুক্ত অ্যারে দিয়ে মাস্ক করতে পারে না

আপনি এ জাতীয় এনএ মানগুলিতে রূপান্তর করতে পারেন False:

df[df["A"].str.contains("Hello|Britain", na=False)]

54
বা আপনি এটি করতে পারেন: ডিএফ [ডিএফ ['এ']। স্ট্রক কন্টেইনস ("হ্যালো | ব্রিটেন", না = মিথ্যা)]
জোশল্ক

2
df[df['A'].astype(str).str.contains("Hello|Britain")]পাশাপাশি কাজ করেছেন
নাগভূষণ এসএন

108

আমি কীভাবে কোনও পান্ডাস ডেটা ফ্রেম থেকে আংশিক স্ট্রিং দ্বারা নির্বাচন করব?

এই পোস্টটি পাঠকদের জন্য যা বোঝাতে চাইছে

  • স্ট্রিং কলামে একটি স্ট্রিংয়ের সন্ধান করুন (সবচেয়ে সহজ কেস)
  • একাধিক সাবস্ট্রিং অনুসন্ধান (অনুরূপ 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

আংশিক স্ট্রিং মেলা আরও বিকল্প: np.char.find, np.vectorize, DataFrame.query

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

পদ্ধতির পরিবার queryevalপরিবার সম্পর্কে আরও তথ্য পিডি.এভাল () ব্যবহার করে পান্ডায় ডায়নামিক এক্সপ্রেশন মূল্যায়ন পাওয়া যায় ।


প্রস্তাবিত ব্যবহারের অগ্রাধিকার

  1. (প্রথম) str.contains, সরলতার জন্য এবং NaNs এবং মিশ্রিত ডেটা হ্যান্ডল করার জন্য
  2. এর কার্য সম্পাদনের জন্য বোধগম্যগুলি তালিকাবদ্ধ করুন (বিশেষত যদি আপনার ডেটা খাঁটি স্ট্রিং হয়)
  3. np.vectorize
  4. (শেষ) df.query

দুই বা ততোধিক কলামে স্ট্রিং সন্ধানের জন্য আপনি কী সঠিক পদ্ধতিতে ব্যবহার করতে পারবেন? মূলত: any(needle in haystack for needling in ['foo', 'bar'] and haystack in (df['col'], df['col2']))এবং তারতম্যগুলি আমি সমস্ত দমবন্ধ চেষ্টা করেছিলাম (এটি সম্পর্কে অভিযোগ any()এবং যথাযথভাবে ... তবে ডক্টর আনন্দের সাথে এ জাতীয় জিজ্ঞাসা কীভাবে করবেন তা অস্পষ্ট।
ডেনিস ডি বার্নার্ডি

@ ডেনিসেডবার্নার্ডিdf[['col1', 'col2']].apply(lambda x: x.str.contains('foo|bar')).any(axis=1)
সিএস 95

@ সিএস 95 + পান্ডাস ডিএফ-এ + পরে হোয়াইটস্পেসযুক্ত স্ট্রেরিং সহ সারিগুলি বের করা হচ্ছে এটি শীঘ্রই উত্তর দেওয়া হয়েছিল, তবে আপনি এটি একবার দেখতে চান।
ankii

@ankiiiiiii দেখে মনে হচ্ছে আপনি আমার উত্তরটির সেই অংশটি মিস করেছেন যেখানে আমি রেইগেক্স মেটাচার্যাক্টরের উল্লেখ করেছি: "কখনও কখনও, আপনার শর্তাদি পাল্টে দেওয়া বুদ্ধিমানের ক্ষেত্রে যদি এমন চরিত্র থাকে যা রেজেক্স মেটাচার্যাক্টর হিসাবে ব্যাখ্যা করা যায়"।
cs95

1
এই ক্ষেত্রে @ 00 স্নাইডার আর একটি কাঁচা স্ট্রিং আক্ষরিক নির্দেশ করতে ব্যবহৃত হয়। এগুলি নিয়মিত প্রকাশের স্ট্রিং লিখতে সহজ করে তোলে। stackoverflow.com/q/2081640
cs95

53

যদি কেউ সম্পর্কিত সমস্যাটি কীভাবে সম্পাদন করবেন তা অবাক করে: "আংশিক স্ট্রিং দ্বারা কলাম নির্বাচন করুন"

ব্যবহার করুন:

df.filter(like='hello')  # select columns which contain the word hello

এবং আংশিক স্ট্রিং মিলের সাহায্যে সারি নির্বাচন axis=0করতে, ফিল্টার করতে পাস করুন:

# selects rows which contain the word hello in their index label
df.filter(like='hello', axis=0)  

6
df.loc[:, df.columns.str.contains('a')]
এটিতে এটি পাতন

18
যা আরও ডিস্টিল করা যেতে পারেdf.filter(like='a')
টেড পেট্রো

এটি একটি নিজস্ব প্রশ্ন + উত্তর হওয়া উচিত, ইতিমধ্যে 50 জন এটির জন্য অনুসন্ধান করেছিল ...
পিভি

1
@ PV8 প্রশ্ন আগে থেকেই আছে: stackoverflow.com/questions/31551412/... । তবে আমি যখন "পান্ডা আংশিক স্ট্রিং দ্বারা কলাম নির্বাচন করুন" এর জন্য গুগলে অনুসন্ধান করি তখন এই থ্রেডটি প্রথম প্রদর্শিত হবে
ফিলিপ শোয়ার্জ

28

দ্রুত দ্রষ্টব্য: আপনি যদি সূচীতে থাকা আংশিক স্ট্রিংয়ের উপর ভিত্তি করে নির্বাচন করতে চান, তবে নিম্নলিখিতটি চেষ্টা করুন:

df['stridx']=df.index
df[df['stridx'].str.contains("Hello|Britain")]

5
আপনি স্রেফ ডিএফ করতে পারেন [df.index.to_series ()। Str.contains ('এলএলচিট')]
ইউরি বায়দা

21

বলুন আপনার নিম্নলিখিত রয়েছে DataFrame:

>>> df = pd.DataFrame([['hello', 'hello world'], ['abcd', 'defg']], columns=['a','b'])
>>> df
       a            b
0  hello  hello world
1   abcd         defg

আপনি inনিজের ফিল্টারটি তৈরি করতে সর্বদা ল্যাম্বডা এক্সপ্রেশনটিতে অপারেটরটি ব্যবহার করতে পারেন ।

>>> df.apply(lambda x: x['a'] in x['b'], axis=1)
0     True
1    False
dtype: bool

কৌতুকটি কলাম অনুসারে কলামের বিপরীতে ল্যাম্বদা ফাংশন সারিতে সারি দ্বারা উপাদানগুলি পাস axis=1করার applyজন্য বিকল্পটি ব্যবহার করা এখানে কৌশলটি trick


X ['a'] কেবলমাত্র x ['b'] এর শুরুতেই বিদ্যমান বলে আমি উপরে কীভাবে সংশোধন করব?
কমপ্লেক্সডাটা

1
কর্মক্ষমতা এবং মেমরির ক্ষেত্রে প্রয়োগটি এখানে একটি খারাপ ধারণা। এই উত্তর দেখুন ।
cs95

8

আংশিক স্ট্রিং ম্যাচের জন্য আমি এখানে যা শেষ করেছি তা এখানে। কারও কাছে যদি এটি করার আরও দক্ষ পদ্ধতি থাকে তবে দয়া করে আমাকে জানান।

def stringSearchColumn_DataFrame(df, colName, regex):
    newdf = DataFrame()
    for idx, record in df[colName].iteritems():

        if re.search(regex, record):
            newdf = concat([df[df[colName] == record], newdf], ignore_index=True)

    return newdf

3
লুপের পূর্বে আপনি রেগেক্স কম্পাইল করে 2x থেকে 3x দ্রুত হওয়া উচিত: regex = re.compile (regex) এবং তারপরে যদি regex.search (রেকর্ড)
মার্কোক্রাম এম

1
@ মারকোক্রাম ডকস.পিথন.আর. / .6 .// library/ re.html # re.compile বলছে যে সর্বাধিক সাম্প্রতিক রেইজেক্সগুলি আপনার জন্য ক্যাশে হয়েছে, সুতরাং আপনার নিজের সংকলনের দরকার নেই।
তিপিম্ম

কোনও ডেটা ফ্রেমের মাধ্যমে পুনরাবৃত্তি করতে ইটারিটাম ব্যবহার করবেন না। এটি পণ্ডিতযোগ্যতা এবং পারফরম্যান্সের ক্ষেত্রে সর্বশেষ স্থানে রয়েছে
সিএস 95

5

ব্যবহারগুলি বিশেষ অক্ষরগুলির সাথে আমার স্ট্রিংয়ের পক্ষে ভাল কাজ করে না। কাজ করা সন্ধান করুন।

df[df['A'].str.find("hello") != -1]

2

এর আগে এমন উত্তর রয়েছে যা জিজ্ঞাসিত বৈশিষ্ট্যটি সম্পন্ন করে, যাইহোক আমি সবচেয়ে সাধারণভাবে দেখাতে চাই:

df.filter(regex=".*STRING_YOU_LOOK_FOR.*")

এই ভাবে চলুন আপনি কলামটি পান যেভাবেই যা লেখা হোক না কেন তার জন্য সন্ধান করুন।

(অবিশ্বাস্যরূপে, আপনাকে প্রতিটি মামলার জন্য সঠিক রেগেক্স এক্সপ্রেশন লিখতে হবে)


1
কলামের শিরোনামে এই ফিল্টারগুলি । এটি সাধারণ নয়, এটি ভুল।
সিএস 95

@ মিশেলডিট্যুইটার যা এখনও ভুল, তার পরিবর্তে সূচী লেবেলে ফিল্টার হবে!
cs95

প্রশ্নের উত্তর দেয় না। তবে আমি কিছু শিখেছি। :)
মিশেল ডি রুইটার

2

সম্ভবত আপনি পান্ডসের ডেটাফ্রেমের সমস্ত কলামে কিছু পাঠ্য অনুসন্ধান করতে চান, এবং কেবল সেগুলির সাবসেটে নয়। এই ক্ষেত্রে, নিম্নলিখিত কোডটি সাহায্য করবে।

df[df.apply(lambda row: row.astype(str).str.contains('String To Find').any(), axis=1)]

সতর্কবাণী। এই পদ্ধতিটি তুলনামূলকভাবে ধীর হলেও সুবিধাজনক।


2

পান্ডাস ডেটা ফ্রেম কলামে স্ট্রিংয়ের জন্য আপনার কেস সংবেদনশীল অনুসন্ধান করা উচিত:

df[df['A'].str.contains("hello", case=False)]
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.