【问题标题】:Combine list that shares common value from two dataframe columns [closed]合并从两个数据框列共享共同值的列表[关闭]
【发布时间】:2021-03-06 07:39:09
【问题描述】:

假设您有两个包含一些列表的数据框列:


python中的代码会是什么样子?

【问题讨论】:

  • 导致最后一个df的逻辑是什么?为什么我们有两行?
  • @aprospero 第一行是有共享公共元素的列表的id,第二列是共享公共元素的元素

标签: python pandas dataframe join merge


【解决方案1】:
df1 = pd.DataFrame(
    {
        'Id':[1,2,3],
        'a':[[1,2,3],[4, 5],[6]]
    }, 
)
df2 = pd.DataFrame(
    {
        'Id':[1,2,3],
        'b':[[3],[6, 7],[8]]
    }, 
)


df3 = pd.DataFrame(
    {
        'Id': [
            [int(df1[pd.Series(map(tuple, df1['a']))  == tuple(i)].index.values)+1, 
             int(df1[pd.Series(map(tuple, df2['b']))  == tuple(j)].index.values)+1] 
            for j in df2['b'] for i in df1['a'] if set.intersection(set(i), set(j))],
        'a&b': [list(set.union(set(i), set(j))) 
                for j in df2['b'] 
                for i in df1['a'] 
                if set.intersection(set(i), set(j))],
    }
)

:输出:

我知道我的解决方案非常混乱,但是当我尝试以其他方式解决时,例如不使用元组压缩,这很容易,然后我得到了各种错误,例如 ValueError: Lengths must match to compare,这是我们都知道的常见问题类型

【讨论】:

  • (df1['a'])) == i).index.values 逻辑优于 int(df1[pd.Series(map(tuple, df1['a'])) == tuple(i) 但第一个会导致很多错误和错误
  • 它说“作为索引器提供的不可对齐的布尔系列(布尔系列的索引和索引对象的索引不匹配)”。我想在具有不同长度的数据框中执行此操作。
【解决方案2】:
  • dfdf1 之间的笛卡尔积开始
  • 接下来查找 ba 子集的行 subset
  • 使用set.union()获取ab的超集
  • 构建 list 的组合 id
  • 一些清理 - dropna() 和你想要的列 loc[]
df = pd.DataFrame({"id":[1,2,3],
             "a":[[1,2,3],[4,5],[6]]})

df1 = pd.DataFrame({"id":[1,2,3],
             "b":[[3],[6,7],[8]]})

df2 = (df.assign(foo=1)
 .merge(df1.assign(foo=1), on="foo")
 .assign(**{"a&b":lambda dfa: np.where(dfa.apply(lambda r: any(x in r.a for x in r.b), axis=1),
                                     dfa.apply(lambda r: list(set(r.a).union(r.b)), axis=1),
                                     np.nan)})
 .dropna()
 .assign(id=lambda dfa: dfa.loc[:,["id_x","id_y"]].apply(list, axis=1))
 .loc[:,["id","a&b"]]
)

id a&b
0 [1, 1] [1, 2, 3]
7 [3, 2] [6, 7]

替代方法

  • 这消除了笛卡尔积的组合爆炸
  • list 爆炸之前复制它,以便轻松重建
(df.assign(a_arr=df.a).explode("a")
 .merge(df1.assign(b_arr=df1.b).explode("b"), left_on="a", right_on="b")
 .assign(**{"id":lambda dfa: dfa.loc[:,["id_x","id_y"]].apply(list, axis=1),
           "a&b":lambda dfa: dfa.loc[:,["a_arr","b_arr"]].apply(lambda r: list(set(r.a_arr).union(r.b_arr)), axis=1)})
 .loc[:,["id","a&b"]]
)

【讨论】:

  • 它说“无法为形状为 (3513454770,) 且数据类型为 int64 的数组分配 26.2 GiB”。发生了什么?
  • 这是笛卡尔积 - 它将生成 len(df) * len(df1) 行。您的 DF 中是否有任何方法可以减少可能的组合数量?
  • 我已经更新了一种不做笛卡尔积的替代方法。组合将取决于列表的大小
猜你喜欢
  • 2021-12-17
  • 2011-06-18
  • 2017-09-03
  • 1970-01-01
  • 2019-10-25
相关资源
最近更新 更多