从列表中删除包含列表中特定值的数据帧行

2024-06-23 19:05:54 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个数据帧df

    A   B   C   D   E
0   string1 string4 [string7, string10, ...] [string11, string 12] [string15, ...]
1   string2 string5 [string8, ...] [string13, ...] [string16, ...]
2   string3 string6 [string9, ...] [string14, ...] [string17, ...]

和一个列表{}:

to_delete = [string7, string9, string17]

我想删除数据框中包含to_delete中字符串的所有行,但我不知道如何将.isin与列表一起使用


Tags: to数据df列表stringdeletestring1string2
3条回答

我知道已经有几个答案了,但如果可以的话,我想加入我的答案。我认为SeaBean's solution也是正确的,我喜欢这一点,与other proposed solution不同,您不必指定哪些列具有列表

我不能像SeaBean那样解释我的解决方案,因为这是我不久前遇到的东西,我诚实地用试错法提出了它

d = {'A':['string1','string2','string3'],
     'B':['string4','string5','string6'],
     'C':[['string7','string10'],['string8'],['string9']],
     'D':[['string11','string12'],['string13'],['string14']]
     'E':[['string15'],['string16'],['string17']]}
df = pd.DataFrame(data=d);
res = df[~df.stack().explode().isin(to_delete).any(level=0)]

我试着用更多的项目来计时,似乎我的解决方案稍微好一点

d = {'A':['string1','string2','string3']*10000, 'B':['string4','string5','string6']*10000, 'C':[['string7','string10'],['string8'],['string9']]*10000,'D':[['string11','string12'],['string13'],['string14']]*10000,'E':[['string15'],['string16'],['string17']]*10000}
df = pd.DataFrame(data=d);

to_delete = ['string7', 'string9', 'string17']


start = time.time()
print(df[~df.stack().explode().isin(to_delete).any(level=0)])
end = time.time()
print(end - start)

start = time.time()
print(df.loc[df.apply(pd.Series.explode).isin(to_delete).groupby(level=0).sum().sum(axis=1).eq(0)])
end = time.time()
print(end - start)

输出:

             A        B          C           D           E
1      string2  string5  [string8]  [string13]  [string16]
4      string2  string5  [string8]  [string13]  [string16]
7      string2  string5  [string8]  [string13]  [string16]
10     string2  string5  [string8]  [string13]  [string16]
13     string2  string5  [string8]  [string13]  [string16]
...        ...      ...        ...         ...         ...
29986  string2  string5  [string8]  [string13]  [string16]
29989  string2  string5  [string8]  [string13]  [string16]
29992  string2  string5  [string8]  [string13]  [string16]
29995  string2  string5  [string8]  [string13]  [string16]
29998  string2  string5  [string8]  [string13]  [string16]
                                                          
[10000 rows x 5 columns]                                  
0.08804535865783691                                       
             A        B          C           D           E
1      string2  string5  [string8]  [string13]  [string16]
4      string2  string5  [string8]  [string13]  [string16]
7      string2  string5  [string8]  [string13]  [string16]
10     string2  string5  [string8]  [string13]  [string16]
13     string2  string5  [string8]  [string13]  [string16]
...        ...      ...        ...         ...         ...
29986  string2  string5  [string8]  [string13]  [string16]
29989  string2  string5  [string8]  [string13]  [string16]
29992  string2  string5  [string8]  [string13]  [string16]
29995  string2  string5  [string8]  [string13]  [string16]
29998  string2  string5  [string8]  [string13]  [string16]
                                                          
[10000 rows x 5 columns]                                  
0.11187744140625                                          

我能想到的最糟糕的解决方案是使用apply

g = lambda x: (set(to_delete) - df[x].apply(set)).str.len()==len(to_delete)

res = df[g('C') & g('D') & g('E')]

df(输入):

    A           B           C                       D                       E
0   string1     string4     [string7, string10]     [string11, string12]    [string15]
1   string2     string5     [string8]               [string13]              [string16]
2   string3     string6     [string9]               [string14]              [string17]

res:

    A           B           C            D          E
1   string2     string5     [string8]   [string13]  [string16]

您可以通过以下步骤接近:

  1. 您可以在每个列/元素上使用pd.Series.explode()将字符串列表展开为多行,每行仅包含字符串(所有列表都已展开/分解为行)

  2. 然后使用.isin()检查数据帧中to_delete列表中的字符串

  3. 按索引级别0分组(在分解之前包含原始行索引),将多行匹配结果聚合并汇总回一行(使用groupby()下的.sum()

  4. 然后.sum(axis=1)按行检查要删除的任何匹配字符串

  5. 检查0匹配的行(要保留的行)并形成结果行的布尔索引

  6. 最后,使用.loc过滤不匹配的行以保留


df.loc[df.apply(pd.Series.explode).isin(to_delete).groupby(level=0).sum().sum(axis=1).eq(0)]

结果:

         A        B          C           D           E
1  string2  string5  [string8]  [string13]  [string16]

可根据以下代码构建原始数据帧以进行测试:

data = {'A': ['string1', 'string2', 'string3'],
 'B': ['string4', 'string5', 'string6'],
 'C': [['string7', 'string10'], ['string8'], ['string9']],
 'D': [['string11', 'string 12'], ['string13'], ['string14']],
 'E': [['string15'], ['string16'], ['string17']]}

 df = pd.DataFrame(data)

相关问题 更多 >

    热门问题