我编写了一个Python脚本,用于通过关键字过滤csv文件中的行。这是我的主要搜索功能:
search_keywords= 'CVE-2017-XX|OpenSSL|XYZ'
df_rest = pd.DataFrame(df_rest[df_rest[[0,1,2,3,4,5]].apply(lambda r: r.str.contains(search_keywords, case=False).any(), axis=1)])
我的问题是如何只过滤包含2或3个关键字的行?
示例:ID, NAME, String1 String2 String3, COMMENT
按关键字过滤:String1, String3
我想仅在两个关键字匹配时才过滤该行。
答案 0 :(得分:2)
我认为你可以为每个关键字创建单独的掩码,然后将它们与&
的链接相结合 - 每行至少一个True
使用DataFrame.any
:
df_rest = pd.DataFrame({0:['OpenSSL XYZ dd','dd OpenSSL','g OpenSSL'],
1:['CVE-2017-XX OpenSSL dd','dd OpenSSL','g XYZ'],
2:['OpenSSL t','dd XYZ','g CVE-2017-XX XYZ OpenSSL']})
cols = [0,1,2]
m1 = df_rest[cols].apply(lambda r: r.str.contains('OpenSSL', case=False))
print (m1)
0 1 2
0 True True True
1 True True False
2 True False True
m2 = df_rest[cols].apply(lambda r: r.str.contains('XYZ', case=False))
print (m2)
0 1 2
0 True False False
1 False False True
2 False True True
m3 = df_rest[cols].apply(lambda r: r.str.contains('CVE-2017-XX', case=False))
print (m3)
0 1 2
0 False True False
1 False False False
2 False False True
print (m1 & m2)
0 1 2
0 True False False
1 False False False
2 False False True
print ((m1 & m2).any(axis=1))
0 True
1 False
2 True
dtype: bool
df = df_rest[(m1 & m2).any(axis=1)]
print (df)
0 1 2
0 OpenSSL XYZ dd CVE-2017-XX OpenSSL dd OpenSSL t
2 g OpenSSL g XYZ g CVE-2017-XX XYZ OpenSSL
编辑:
可能有些关键字被解释为正则表达式。为避免使用regex=
False
:
df_rest = pd.DataFrame({0:['XYZ dd','dd OpenSSL 0.9.4','g 0.9.4'],
1:['0.9.4 OpenSSL dd','dd 0.9','g XYZ'],
2:['OpenSSL t','dd XYZ','OpenSSL 0.9.7']})
print (df_rest)
0 1 2
0 XYZ dd 0.9.4 OpenSSL dd OpenSSL t
1 dd OpenSSL 0.9.4 dd 0.9 dd XYZ
2 g 0.9.4 g XYZ OpenSSL 0.9.7
cols = [0,1,2]
m = df_rest[cols].apply(lambda r: (r.str.contains('0.9.4', case=False, regex=False) &
r.str.contains('OpenSSL', case=False, regex=False)))
df = df_rest[m.any(axis=1)]
print (df)
0 1 2
0 XYZ dd 0.9.4 OpenSSL dd OpenSSL t
1 dd OpenSSL 0.9.4 dd 0.9 dd XYZ
EDIT1:
df_rest = pd.DataFrame({0:['XYZ dd','dd OpenSSL 0.9.1','g 0.9.4'],
1:['0.9.2 OpenSSL dd','dd 0.9','g XYZ'],
2:['OpenSSL t','dd XYZ','OpenSSL 0.9.1']})
print (df_rest)
df = pd.read_csv('keywords.txt', names=('a','b'))
print (df)
a b
0 OpenSSL 0.9.1
1 OpenSSL 0.9.2
2 OpenSSL 0.9.4
cols = [0,1,2]
for i, x in df.iterrows():
m = df_rest[cols].apply(lambda r: (r.str.contains(x['a'], case=False, regex=False) &
r.str.contains(x['b'], case=False, regex=False)))
df = df_rest[m.any(axis=1)]
f = '{0[0]}_{0[1]}.txt'.format((x['a'], x['b']))
df.to_csv(f, index=False, header=False)
EDIT2:
dfs = []
for i, x in dfkey.iterrows():
cols = [0,1,2,3,4,5]
m = df_rest[cols].apply(lambda r: (r.str.contains(x['a'], case=False, regex=False) &
r.str.contains(x['b'], case=False, regex=False)))
df_rest = df_rest[m.any(axis=1)]
dfs.append(df_rest)
pd.concat(dfs).to_csv('text.csv', index=False, header=False)