【问题标题】:Filter Data by multiple keywords按多个关键字过滤数据
【发布时间】:2017-10-13 16:48:30
【问题描述】:

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

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

【问题讨论】:

  • 您是在搜索 CSV 还是数据框?
  • 你能编辑你的问题,显示你的df。发布您的 df 和所需的输出

标签: python pandas filter


【解决方案1】:

我认为您可以为每个关键字创建单独的掩码,然后将它们与& 的链接结合起来 - 每行至少有一个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

编辑1:

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) 

【讨论】:

  • 一如既往的快!
  • 当然我在考虑相同的解决方案,所以最好确认它是正确的
  • 我正在使用一个keyword.txt 文件。这是我的问题。我也试过这个: df_rest = pd.DataFrame(df_rest[df_rest[[0,1,2,3,4,5]].apply(lambda r: (r.str.contains('OpenSSL', case=False) .any()) 和 (r.str.contains('0.9.4', case=False).any()), axis=1)]) 但它也过滤 0.9 而不是 0.9.4
  • 不,因为点:0.9.4,它拆分了我的字符串
  • 我是这样做的:df_rest = pd.DataFrame(df_rest[df_rest[[0,1,2,3,4,5]]].apply(lambda r: (r.str.contains (x[0], case=False, regex=True).any()) 和 (r.str.contains(x[1], case=False, regex=True).any()), axis=1) ]) for i, x in dfkey.iterrows(): if (i == 0): df = pd.concat([df_header, df_rest], axis=0) df = df.reset_index(drop=True) df.to_csv (csv_tempfile, index=True, header=None) if (i >= 1): df.to_csv(csv_tempfile, mode='a', header=False)
猜你喜欢
  • 2016-11-20
  • 1970-01-01
  • 1970-01-01
  • 2015-10-14
  • 2019-12-30
  • 1970-01-01
  • 2017-12-07
  • 2019-09-29
  • 1970-01-01
相关资源
最近更新 更多