如何检查一个熊猫列中列表中的所有元素是否存在于另一熊猫列中

时间:2020-02-28 19:06:23

标签: python pandas list dataframe dictionary

我在数据框df1的一列中有一个列表,我想检查每一行是否该列表的所有元素都在第二个数据框df2中的另一列中。

两个数据框是这样的:

df1                                          df2

id | members      |                          num  |  available           |
1  |['a',b']      |                          one  | ['a','b','c','d','e']|
2  |['b']         |                          two  | ['a','b']            |
3  |['a','b','c'] |                          three| ['b','d','e']        |

我正在尝试提出一种方法,该方法可以为df2中的每一行提供members中哪些行具有df1的所有元素。也许是这样的:


id | members      | which_cols            |                
1  |['a',b']      | ['one','two']         |                       
2  |['b']         | ['one','two','three'] |                         
3  |['a','b','c'] | ['one']               |                      

我认为将其转换为{k: list(v) for k,v in df1.groupby("id")["members"]}{i: list(j) for i,j in df2.groupby("num")["available"]}之类的字典可能会使其更灵活地实现所需的输出,但仍然找不到找到我要寻找的方法。

df2将具有约300行,其中available的长度与25,000一样大。而且df1可以和1M行一样大,列表长度在members中最多为15。因此,我认为效率也很重要。

1 个答案:

答案 0 :(得分:0)

问题的核心在于您的数据设置。如果您进行一些预处理,则可以避免繁琐地遍历每个列表多次。

设置

df1 = pd.Series([['a', 'b'], ['b'], ['a', 'b', 'c']], name = 'members').to_frame()
df2 = pd.Series([['a', 'b', 'c', 'd', 'e'], 
                  ['a', 'b'],
                  ['b', 'd', 'e']], name = 'available').to_frame()
df2.index = ['one', 'two', 'three']

>>> df1

    members
0   ['a', 'b']
1   ['b']
2   ['a', 'b', 'c']

>>> df2

        available
one.    ['a', 'b', 'c', 'd', 'e']
two     ['a', 'b']
three   ['b', 'd', 'e']

重塑数据

如果您在处理数据之前先对数据进行一次编码,那么您在进行子集检查方面将有很大的优势:

# You can do this many ways, but sklearn makes this very easy with:
from sklearn.preprocessing import MultiLabelBinarizer

mlb = MultiLabelBinarizer()
df1 = df1.join(pd.DataFrame(mlb.fit_transform(df1.pop('members')),
                          columns=mlb.classes_, index=df1.index))

mlb = MultiLabelBinarizer()
df2 = df2.join(pd.DataFrame(mlb.fit_transform(df2.pop('available')),
                          columns=mlb.classes_, index=df2.index))

>>> df1
    a   b   c
0   1   1   0
1   0   1   0
2   1   1   1


>>> df2
        a   b   c   d   e
one     1   1   1   1   1
two     1   1   0   0   0
three   0   1   0   1   1

计算

关于这种数据格式的聪明之处在于,现在您可以从df1中减去df2,并且如果所有结果值都不为-1(表明{{1}中没有元素},然后将其添加到列表中。您可以将其视为覆盖两个数据帧(对齐每个资源)然后减去。当然,可以将其向量化:

df2