我有一个名为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.结果应为
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
感谢您的帮助。
答案 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,))