如何找到与熊猫匹配的指定字符串匹配过滤器模式

时间:2018-11-20 11:57:26

标签: python pandas

我有一个名为tf的熊猫数据集,该数据集的一列包含标题为“关键字”的空格分隔的关键字:

Name         ...                    Keywords
0  Jonas 0         ...                Archie Betty
1  Jonas 1         ...                      Archie
2  Jonas 2         ...          Chris Betty Archie
3  Jonas 3         ...                 Betty Chris
4  Jonas 4         ...                       Daisy
5  Jonas 5         ...                         NaN
6  Jonas 5         ...                Chris Archie

作为输入,我想提供一组字符串以通过这些关键字过滤行。我考虑过使用列表:

list = ["Chris", "Betty"]

我发现,如果我将列表做成一个字符串,并用“ |”分隔条目,则可以过滤行:

t="|".join(list)

,然后使用以下命令在该列中查找匹配项:

tf[tf["Keywords"].str.contains(t, na=False)]

这会通过查找任何匹配的内容进行过滤,因此输出为:

Name         ...                    Keywords
0  Jonas 0         ...                Archie Betty
2  Jonas 2         ...          Chris Betty Archie
3  Jonas 3         ...                 Betty Chris
6  Jonas 5         ...                Chris Archie

我想要的是:

  1. 仅包含列表条目和

  2. 进行过滤
  3. 通过至少包含列表条目进行过滤

对于1.结果应为

3 Jonas 3 ... Betty Chris

对于2.,结果应为:

2  Jonas 2         ...          Chris Betty Archie
3  Jonas 3         ...                 Betty Chris

我发现以下内容基本上可以解决2问题。

a = tf["Keywords"].str.contains("Chris")
b = tf["Keywords"].str.contains("Betty")
tf[a&b]

但是,由于列表长度及其条目可能会有所不同,因此我需要对此进行通用处理。我有一个笨拙的主意,有一个循环来使每两个连续的列表项相交,但这没用:

i = 0
while i < len(list)-1:
    a = tf["Keywords"].str.contains(list[i])
    b = tf["Keywords"].str.contains(list[i+1])
    tf = a & b
    i += 1

感谢您的帮助。

4 个答案:

答案 0 :(得分:0)

通知:

不要使用变量名list,因为python代码字。


如果所有关键字都只有一个词,且之间没有空格,则解决方案:

您可以按空格分割所有单词并将其转换为set,因此可以通过从列表L转换而来的集合进行比较:

L = ["Chris", "Betty"]
s = set(L)

arr = np.array([set(x.split()) if isinstance(x, str) else set([]) for x in tf["Keywords"]])
print (arr)
[{'Archie', 'Betty'} {'Archie'} {'Chris', 'Archie', 'Betty'}
 {'Chris', 'Betty'} {'Daisy'} set() {'Chris', 'Archie'}]

df1 = tf[arr == s]
print (df1)
      Name     Keywords
3  Jonas 3  Betty Chris

df2 = tf[arr >= s]
print (df2)
      Name            Keywords
2  Jonas 2  Chris Betty Archie
3  Jonas 3         Betty Chris

使用关键字中的多个单词的更通用的解决方案:

print (tf)
      Name                  Keywords
0  Jonas 0              Archie Betty
1  Jonas 1                    Archie
2  Jonas 2        Chris Betty Archie
3  Jonas 3               Betty Chris
4  Jonas 4  Daisy Chris Archie Betty
5  Jonas 5                       NaN
6  Jonas 5        Chris Archie Betty

L = ["Chris Archie", "Betty"]
s = set(L)

#create pattern with word boundaries
pat = '|'.join(r"\b{}\b".format(x) for x in L)

#extract all keywords and convert to sets
a = tf['Keywords'].str.findall('('+ pat + ')')
a = np.array([set(x) if isinstance(x, list) else set([]) for x in a])
#remove all matched keywords and remove possible traling whitespaces
b = tf['Keywords'].str.replace(pat, '').str.strip()

#compare only matched values and also empty value after replace
df1 = tf[(b == '') & (a == s)]
print (df1)
      Name            Keywords
6  Jonas 5  Chris Archie Betty

#same like one keyword solution
df2 = tf[a >= s]
print (df2)
      Name                  Keywords
4  Jonas 4  Daisy Chris Archie Betty
6  Jonas 5        Chris Archie Betty

答案 1 :(得分:0)

我认为这是您正在寻找的更多东西,pandas数据框单元格实际上可以包含列表:

import pandas

# Create a test dataframe
df = pandas.DataFrame(
    [
        {"name": "A", "keywords": "Something SomethingElse"},
        {"name": "B", "keywords": "SomethingElse Tada"},
        {"name": "C", "keywords": "Something SomethingElse AndAnother"},
    ]
)

# Split the keywords INSIDE the cell
df["keywords"] = df["keywords"].apply(lambda row: row.split(" "))

# Filter for a specific keyword
filter_terms = ["Something"]
filtered = df.loc[df["keywords"].apply(lambda row: any([term in filter_terms for term in row]))]

# Show the filtered results
print(filtered)

答案 2 :(得分:0)

只需使用

添加您暗含的信息即可

仅模拟DataFrame:

>>> df
      Name            Keywords
0  Jonas 0        Archie Betty
1  Jonas 1              Archie
2  Jonas 2  Chris Betty Archie
3  Jonas 3         Betty Chris
4  Jonas 4               Daisy
5  Jonas 5                 NaN

在使用str.contains分隔的名称时使用|

>>> df[df.Keywords.str.contains("Chris|Betty", na=False)]
      Name            Keywords
0  Jonas 0        Archie Betty
2  Jonas 2  Chris Betty Archie
3  Jonas 3         Betty Chris

现在,如果我们有多个名称搜索,则通过将pattern中的单词与|连接起来来构造正则表达式,从而应用模式基础搜索:

>>> pattern
['Chris', 'Betty']

>>> df[df.Keywords.str.contains('|'.join(pattern), na=False)]
      Name            Keywords
0  Jonas 0        Archie Betty
2  Jonas 2  Chris Betty Archie
3  Jonas 3         Betty Chris

答案 3 :(得分:0)

def compset(x, mylist):
    y = set(x.lower().split())
    if len(y.intersection(mylist)) > 1:  # == 2 for exact match
        return True
    else:
        return False

mylist=set('chris betty'.lower().split())

df['Keywords'].apply(compset, args=(mylist,))