我有一个熊猫DataFrame,其中包含一列字符串值。我需要根据部分字符串匹配来选择行。
类似于这个成语:
re.search(pattern, cell_in_question)
返回布尔值。我熟悉df[df['A']==“helloworld”]的语法,但似乎找不到一种方法来处理部分字符串匹配,比如“hello”。
我有一个熊猫DataFrame,其中包含一列字符串值。我需要根据部分字符串匹配来选择行。
类似于这个成语:
re.search(pattern, cell_in_question)
返回布尔值。我熟悉df[df['A']==“helloworld”]的语法,但似乎找不到一种方法来处理部分字符串匹配,比如“hello”。
当前回答
在此之前,有一些答案可以实现所要求的功能,无论如何,我想展示最普遍的方式:
df.filter(regex=".*STRING_YOU_LOOK_FOR.*")
这样,你就可以得到你所寻找的专栏,无论它是怎么写的。
(显然,您必须为每种情况编写正确的正则表达式)
其他回答
这是我最后为部分字符串匹配所做的。如果有人有更有效的方法,请告诉我。
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
如何从panda DataFrame中选择部分字符串?
这篇文章是为那些想
在字符串列中搜索子字符串(最简单的情况),如df1[df1['col'].str.contains(r'fo(?!$)')]搜索多个子字符串(类似于isin),例如,使用df4[df4['col'].str.contains(r'fo|baz')]匹配文本中的整个单词(例如,“blue”应匹配“the sky is blue”,而不是“bluejay”),例如,与df3[df3['col'].str.contains(r'\bble\b')]匹配匹配多个整词了解“ValueError:无法使用包含NA/NaN值的向量进行索引”背后的原因,并使用str.contains('pattern',NA=False)进行更正
……并希望了解更多关于哪些方法应优于其他方法的信息。
(补充:我看到了很多关于类似主题的问题,我觉得把这个留在这里会很好。)
友好的免责声明,这篇文章很长。
基本子字符串搜索
# 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
有时不需要正则表达式搜索,因此指定正则表达式=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:无法使用包含NA/NaN值的向量进行索引
这通常是因为对象列中存在混合数据或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
如何同时将此应用于多个列?答案就在问题中。使用DataFrame.apply:
# `axis=1` tells `apply` to apply the lambda function column-wise.
df.apply(lambda col: col.str.contains('foo|bar', na=False), axis=1)
A B
0 True True
1 True False
2 False True
3 True False
4 False False
5 False False
下面的所有解决方案都可以使用逐列应用方法“应用”到多个列(这在我的书中是可以的,只要你没有太多列)。
如果您的DataFrame具有混合列,并且希望只选择对象/字符串列,请查看select_dtypes。
多个子字符串搜索
这最容易通过使用正则表达式或管道进行正则表达式搜索来实现。
# 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)]
在列表comp中使用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)]
Use,
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和list compressions之外,还可以使用以下替代方法。
np.char.find仅支持子字符串搜索(读取:无正则表达式)。
df4[np.char.find(df4['col'].values.astype(str), 'foo') > -1]
col
0 foo abc
1 foobar xyz
np.vectorize这是一个围绕循环的包装器,但开销比大多数pandasstr方法小。
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解决方案:
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
数据框架查询通过python引擎支持字符串方法。这没有明显的性能优势,但了解是否需要动态生成查询还是很有用的。
df1.query('col.str.contains("foo")', engine='python')
col
0 foo
1 foobar
有关查询和eval方法族的更多信息,请访问Pandas中的公式动态计算表达式。
推荐使用优先级
(第一)str.contains,因为它简单且易于处理NaN和混合数据列出其性能的理解(尤其是如果数据是纯字符串)np.vectorize(最后)df.query
我在ipython笔记本电脑的macos上使用熊猫0.14.1。我尝试了上面的建议行:
df[df["A"].str.contains("Hello|Britain")]
并得到一个错误:
无法使用包含NA/NaN值的矢量进行索引
但当添加了“==True”条件时,效果非常好,如下所示:
df[df['A'].str.contains("Hello|Britain")==True]
也许您想在Pandas数据帧的所有列中搜索一些文本,而不仅仅是在它们的子集中。在这种情况下,以下代码将有所帮助。
df[df.apply(lambda row: row.astype(str).str.contains('String To Find').any(), axis=1)]
警告这种方法虽然方便,但速度相对较慢。
在此之前,有一些答案可以实现所要求的功能,无论如何,我想展示最普遍的方式:
df.filter(regex=".*STRING_YOU_LOOK_FOR.*")
这样,你就可以得到你所寻找的专栏,无论它是怎么写的。
(显然,您必须为每种情况编写正确的正则表达式)