回答:
github issue #620に基づいて、次のことをすぐに実行できるようになります:
df[df['A'].str.contains("hello")]
更新:ベクトル化された文字列メソッド(つまり、Series.str)は、pandas 0.8.1以降で使用できます。
df[df['A'].str.contains("Hello|Britain")]
df[df['value'].astype(str).str.contains('1234.+')]
非文字列型の列を除外するため。
私は上記の提案された解決策を試しました:
df[df["A"].str.contains("Hello|Britain")]
エラーが発生しました:
ValueError:NA / NaN値を含む配列でマスクすることはできません
次のFalse
ように、NA値をに変換できます。
df[df["A"].str.contains("Hello|Britain", na=False)]
df[df['A'].astype(str).str.contains("Hello|Britain")]
同様に働いた
pandas DataFrameから部分文字列で選択するにはどうすればよいですか?
この投稿は、読者が
isin
)...そして、他の方法よりも優先される方法について詳しく知りたい。
(追記:同様のトピックについて多くの質問を見てきました。ここに残しておくとよいと思いました。)
# 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
s
部分文字列検索を実行し、結果をフィルタリングすると、
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
これは、正規表現ORパイプを使用した正規表現検索によって最も簡単に実現できます。
# 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\\^'
デフォルトでは、部分文字列検索は、指定された部分文字列/パターンがフルワードかどうかに関係なく検索します。完全な単語にのみ一致させるには、ここで正規表現を使用する必要があります\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
v / s
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
「col」に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
Pythonエンジンを介して文字列メソッドをサポートします。これには目に見えるパフォーマンス上の利点はありませんが、クエリを動的に生成する必要があるかどうかを知るのに役立ちます。
df1.query('col.str.contains("foo")', engine='python')
col
0 foo
1 foobar
メソッドquery
とそのeval
ファミリの詳細については、pd.eval()を使用したパンダでの動的式評価をご覧ください。
str.contains
、その単純さとNaNと混合データの扱いやすさのためnp.vectorize
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)
誰かが関連する問題を実行する方法を疑問に思っている場合:「部分的な文字列で列を選択してください」
使用する:
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)
df.loc[:, df.columns.str.contains('a')]
df.filter(like='a')
あなたが次のものを持っているとしましょう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
要素を列ごとではなく行ごとにラムダ関数に渡すことです。
これが、文字列の部分一致に使用した結果です。誰かがこれを行うより効率的な方法を持っている場合は、私に知らせてください。
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
これの前に、質問された機能を実現する答えがあります。とにかく、最も一般的な方法を示したいと思います。
df.filter(regex=".*STRING_YOU_LOOK_FOR.*")
このようにして、書いた方法に関係なく、探している列を取得しましょう。
(当然のことながら、各ケースに適切な正規表現を記述する必要があります)