按多个关键字过滤数据

时间:2017-10-10 06:38:10

标签: python pandas filter

我编写了一个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

我想仅在两个关键字匹配时才过滤该行。

1 个答案:

答案 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)