【问题标题】:Python, Pandas: check each element in list values of column to exist in other dataframePython,Pandas:检查列的列表值中的每个元素是否存在于其他数据框中
【发布时间】:2021-07-10 16:27:40
【问题描述】:

我有一个数据框列,其中包含列表中的值,如果它们在其他数据框中,想要添加具有列表中过滤值的新列。

df:

df = pd.DataFrame({'a':[1,2,5,7,9],'b':[[10,1,'xxx'],[],[1,2,3],[5],[25,27]]})
**a**|**b**
:-----:|:-----:
1|[10, 1, 'xxx']
2|[]
5|[1, 2, 3]
7|[5]
9|[25, 27]

df2:

df2 = pd.DataFrame({'d':[324,21,4353,345,4535,23],'e':[5,1,23,25,25,'xxx']})

我需要在df 中添加带有过滤列b 的新列,以便它包含仅包含df2e 中的元素的列表。

结果:

**a**|**b**|**c**
:-----:|:-----:|:-----:
1|[10, 1, 'xxx']|[1,'xxx']
2|[]|[]
5|[1, 2, 3]|[1]
7|[5]|[5]

速度至关重要,因为有大量记录。

我现在做了什么:

  1. 创建了一组可能的值
l = list(df2['e'].unique())  
  1. 尝试将df.assign 与综合列表一起使用,但效果不佳且速度太慢。
df.assign(mapped=[[x for x in row if x in l] for row in df.b])

感谢任何帮助。

更新

在列表和 df2 中并不总是整数值,有时是字符串。

【问题讨论】:

    标签: python pandas list dataframe mapping


    【解决方案1】:

    您可以尝试投射到 str 然后 series.str.findall

    l = map(str,df2['e'].unique())
    df['c'] = df['b'].astype(str).str.findall('|'.join([fr"\b{i}\b" for i in l]))
    

    findall 模式中的或更短的内容由 @Shubham 提供:

    l = map(str,df2['e'].unique())
    df['c'] = df['b'].astype(str).str.findall(fr"\b({'|'.join(l)})\b")
    

    print(df)
    
       a             b     c
    0  1  [10, 1, 100]   [1]
    1  2            []    []
    2  5     [1, 2, 3]   [1]
    3  7           [5]   [5]
    4  9      [25, 27]  [25]
    

    【讨论】:

    • 对不起,没有提到 - 它不完全是 int 值,有时是字符串,有时是 float/int 作为字符串。所以最好将所有内容都视为字符串。
    • @Oleksii 如果一切都是字符串并假设列表是正确的列表而不是列表的字符串表示:使用 l = df2['e'].unique()df['c'] = df['b'].astype(str).str.findall(fr"\b({'|'.join(l)})\b") ,但如果你有混合 dtypes 你仍然需要较早的答案转换为字符串
    • 好的,谢谢!您能否帮忙修改以将结果存储在 c 列中,而不是列表,而是以逗号分隔的字符串?
    • @Oleksii .map(','.join) 在最后一行的代码之后? df['b'].astype(str).str.findall(fr"\b({'|'.join(l)})\b").map(','.join)
    【解决方案2】:

    你可以使用np.intersect1d()如下:

    l = df2['e'].unique()     # unique() already returns ndarray, no need to use list()
    
    df['c'] = df['b'].map(lambda x: np.intersect1d(x, l))
    
    
    print(df)
    
       a             b     c
    0  1  [10, 1, 100]   [1]
    1  2            []    []
    2  5     [1, 2, 3]   [1]
    3  7           [5]   [5]
    4  9      [25, 27]  [25]
    

    编辑

    根据OP对混合类型数据的编辑,我们只需要修改df2的列e的唯一值的提取方式。无需更改创建列c的主要代码。

    l = list(map(str, df2['e'].unique()))        # only change this
    
    df['c'] = df['b'].map(lambda x: np.intersect1d(x, l))
     
    
    print(df)
    
    
       a             b         c
    0  1  [10, 1, xxx]  [1, xxx]
    1  2            []        []
    2  5     [1, 2, 3]       [1]
    3  7           [5]       [5]
    4  9      [25, 27]      [25]
    

    【讨论】:

    • 不错,尚未测试,但我认为这可能比我的更快,因为字符串转换开销。
    • 对不起,没有提到 - 它不仅是 int 值,有时是字符串,有时是 float/int 作为字符串。
    • @Oleksii 我使用 numpy 函数的解决方案没有假设数据类型是否为字符串、int 或 float 甚至混合类型,并且 numpy 也支持这些类型。而且我不需要任何类型转换。所以,没问题。
    • @Oleksii 微调解决方案以支持您对混合类型进行编辑。
    • @Oleksii 哦,通常 numpy 函数应该运行得很快。在这种情况下,可能是因为我们需要在 Pandas 和 numpy 之间进行接口,而 map() 函数只是迭代调用 np.intersect1d 而没有优化矢量化操作。我试图以另一种方式将其称为np.intersect1d(df['b'], l),但它似乎不接受该系列,因为它是 2D 而不是以列表为元素的 1D。继续使用更快的。 :-)
    猜你喜欢
    • 1970-01-01
    • 2022-10-07
    • 1970-01-01
    • 2021-09-27
    • 2022-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多