【问题标题】:Writing python dictionary from dataframe checking intersections between values从数据框编写python字典检查值之间的交叉点
【发布时间】:2018-03-12 17:44:08
【问题描述】:

我必须从同一个 csv 文件中编写三个字典。输入文件是

col1   col2   value
item1  a      value1
item1  b      value2
item1  c      value3
item2  a      value4
item2  c      value5
...

我需要这三个字典:

1.

dict1
item1:set(a,b,c)
item2:set(a,c)
...

2.

dict2
set(item1,a):value1
set(item1,b):value2
set(item1,c):value3
set(item2,a):value4
set(item2,c):value5

我需要在第一个字典中使用集合作为值,因为那样我将不得不在值之间执行交集,我认为集合是更合适的类型。

我的最终字典,由这些交叉点产生,将类似于:

3.

dict3
(item1,item2):value1+value3 

看例子可能更容易理解,但让我解释一下:基本上dict3考虑dict1的值之间的成对交集,在我的例子中只有a,然后是dict2.get((item1,a))+dict2.get((item2,a))并将其作为值分配给这对夫妇(item1,item2)。如果 item1 和 item2 有共同的另一个元素,比如d,那么(item1,item2) 的值将是dict2.get((item1,a))+dict2.get((item2,a))+dict2.get((item1,d))+dict2.get((item2,d))。请注意,在真实数据集中 col1 和 col2 项目是字符串。 重复此计算,检查 dict1 中值的每个成对交集。

获取这些词典最简单的方法是什么?我更喜欢使用 pandas,所以我希望您建议使用数据框的解决方案,但我也可以接受直接从外部文件读取的任何内容,因为这仅在第一阶段发挥作用。

编辑我可能应该更好地澄清我需要一个 pairwise 交集,而我给出的示例不会出现这个问题。为了有一个更好的例子,可以尝试:

df=pd.DataFrame(columns=['col1','col2','value']) 
df.col1=['item1','item1','item1','item2','item2','item3','item3'] 
df.col2=['a','b','c','a','d','a','c'] 
df.value=[1,2,3,4,5,6,7] 

并尝试得到结果:

dict3
(item1,item2):5
(item1,item3):17
(item2,item3):10

这似乎是一个非常复杂的问题:我在成对集合交集here 上找到了一些东西,但我找不到最终解决方案。

【问题讨论】:

    标签: python python-3.x pandas dictionary


    【解决方案1】:

    如果您不关心有多少项目匹配,则以下方法有效(请参阅下文,了解如何仅通过成对匹配进行此操作):

    In [1]: df
    Out[1]:
        col1 col2  value
    0  item1    a      1
    1  item1    b      2
    2  item1    c      4
    3  item2    a      8
    4  item2    d     16
    
    In [2]: dict1 = df.groupby('col1').apply(lambda vals: set(vals.col2))
    
    In [3]: dict1
    Out[3]:
    col1
    item1    {b, c, a}
    item2       {a, d}
    dtype: object
    
    In [4]: dict3 = {tuple(sorted(vals.col1)): sum(vals.value)
                     for kind, vals in df.groupby('col2')
                     if kind in set.intersection(*[dict1[itm] for itm in vals.col1])
                     and len(vals) > 1}
    
    In [5]: dict3
    Out[5]: {('item1', 'item2'): 9}
    

    编辑:

    要以成对的方式执行此操作,让我们使用修改后的连接:

    df.reset_index(inplace=True)
    
    merged = pd.merge(df, df, on='col2')
    merged = merged[merged.index_x < merged.index_y]
    
    idxs, vals = zip(*[(tuple(sorted([row.col1_x, row.col1_y])), row.value_x + row.value_y)
        for row in merged.itertuples(False)])
    final = pd.DataFrame(list(vals), index=list(idxs))
    

    我们的价值观是:

    In [1]: df
    Out[1]:
       index   col1 col2  value
    0      0  item1    a      1
    1      1  item1    b      2
    2      2  item1    c      3
    3      3  item2    a      4
    4      4  item2    d      5
    5      5  item3    a      6
    6      6  item3    c      7
    
    In [2]: merged
    Out[2]:
        index_x col1_x col2  value_x  index_y col1_y  value_y
    1         0  item1    a        1        3  item2        4
    2         0  item1    a        1        5  item3        6
    5         3  item2    a        4        5  item3        6
    11        2  item1    c        3        6  item3        7
    
    In [3]: final
    Out[3]:
                     0
    (item1, item2)   5
    (item1, item3)   7
    (item2, item3)  10
    (item1, item3)  10
    

    merge 操作可能会占用相当多的内存,具体取决于您的数据大小。 Pandas doesn't support a more complex merge function 这也会考虑到我们的不等式,据我所知,如果不自己编写 join 函数(你可以用字典理解来做到这一点——见下文)。不过,真的,如果数据大小是一个很大的问题,您可能需要考虑使用 Spark 数据帧,它应该更具可扩展性(如果您只在一台计算机上,我不知道这是否一定是真的,但是我怀疑它是)不需要显着不同的代码。

    要使用字典理解来做到这一点,我认为您的代码可能如下所示:

    final_dict = {
        tuple(sorted((a.col1, b.col1))): a.value + b.value
        for a_index, a in df.iterrows()
        for b_index, b in df.iterrows()
        if a_index < b_index
        and a.col2 == b.col2
    }
    
    # {('item1', 'item2'): 5, ('item1', 'item3'): 10, ('item2', 'item3'): 10}
    

    请注意字典如何无形地覆盖重复的键条目,而 Pandas 会尝试保留它们。只是模棱两可,让您决定如何解决。

    【讨论】:

    • 抱歉,ac 之间的冲突导致只有 c 的值出现在最终字典中。修复它以更好地反映您的示例输出(通过稍微调整您的示例输入)
    • 或多或少:这样 dict3 中的输出,考虑到在真实数据集中我有更多项目,是(item1, item2,item3,...item n):###,因为我认为它需要所有这些项目之间的交集并总结这些值.但我特别需要键中的两项,因为最终它必须是某种成对交互的字典
    • df=pd.DataFrame(columns=['col1','col2','value']) df.col1=['item1','item1','item1','item2','item2','item3','item3'] df.col2=['a','b','c','a','d','a','c'] df.value=[1,2,3,4,5,6,7]
    • 谢谢@scnerd!如果最后我调用 final.groupby().sum ,它完全符合我的需要。我会将此标记为正确答案,但实际上我有内存问题:数据集非常大,800gb 的内存是不够的。即使我从未使用过 Spark 数据帧,我也会尝试它。
    • 很高兴听到这有帮助。是的,当您开始谈论 100 GB 的数据时,最好转移到某种分布式框架(例如 Spark)。 Pandas 对小规模数据非常强大,但它并不是为处理真正的大规模问题而设计的。如果您可以使用 PySpark 的数据框 API,那么过渡应该不会太难。祝你好运。
    猜你喜欢
    • 2018-03-06
    • 2022-11-02
    • 1970-01-01
    • 1970-01-01
    • 2018-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-24
    相关资源
    最近更新 更多