代码之家  ›  专栏  ›  技术社区  ›  sacuL

基于另一个数据帧在Pandas中创建新列

  •  2
  • sacuL  · 技术社区  · 7 年前

    我需要根据第二个数据帧的属性向现有熊猫数据帧添加一列。我举了一个简单的例子来说明我的确切要求。

    我有两个数据帧,一个表示成对的名称,另一个表示两个个体之间的交互:

        >>> names
        id_a   id_b
    0    ben   jack
    1   jack    ben
    2   jill   amir
    3  wilma   jill
    4   amir  wilma
    
    >>> interactions
      individual1 individual2
    0        jill        jack
    1        jack        jill
    2       wilma        jill
    3        amir        jill
    4        amir        jack
    5        jack        amir
    6        jill        amir
    

    我需要的基本上是:对于 names ,我需要计算这两个名称之间的交互次数 interactions 在哪儿 names['id_a'] 要么是 interactions['individual1'] interactions['individual2'] 以及 names['id_b'] 要么是 交互['individual1'] 交互['individual2'] . 此计数需要包含在列中 num_interactions 对于名称中的所有行,即使名称重复(即,如果有一行id\u a是ben,id\u b是jack,而有一行这些名称是颠倒的(id\u a是jack,id\u b是ben),这两行都应包含num\u交互)

    生成的数据帧如下所示:

    >>> names
        id_a   id_b  num_interactions
    0    ben   jack               0.0
    1   jack    ben               0.0
    2   jill   amir               2.0
    3  wilma   jill               1.0
    4   amir  wilma               0.0
        enter code here
    

    我所做的一切

    这很好用,但很难看,很难读,效率很低,我知道一定有更好的方法!也许是某种形式的合并,但我真的不知道它如何适用于复杂的标准。。。

    for i in range(len(names)):
        names.loc[i, 'num_interactions'] = len(
            interactions[((interactions['individual1'] == names.loc[i, 'id_a']) &
                          (interactions['individual2'] == names.loc[i, 'id_b'])) |
                         ((interactions['individual2'] == names.loc[i, 'id_a']) &
                          (interactions['individual1'] == names.loc[i, 'id_b']))
                         ])
    

    复制示例数据帧

    如果您想处理这个问题,可以使用它来复制上面的虚拟数据帧。

    import pandas as pd
    names = pd.DataFrame(data={'id_a': ['ben', 'jack', 'jill', 'wilma', 'amir'],
                               'id_b': ['jack', 'ben', 'amir', 'jill', 'wilma']})
    
    interactions = pd.DataFrame(data={'individual1': ['jill', 'jack',
                                                      'wilma', 'amir',
                                                      'amir', 'jack', 'jill'],
                                      'individual2': ['jack', 'jill', 'jill',
                                                      'jill', 'jack', 'amir',
                                                      'amir']})
    

    提前感谢!

    2 回复  |  直到 7 年前
        1
  •  1
  •   cs95 abhishek58g    7 年前

    假设顺序无关紧要,您可以按列对每个数据帧进行排序。对于第二个数据帧,计算每组与 groupby + count 然后执行左外侧 merge 在结果和第一个数据帧上。

    i = pd.DataFrame(np.sort(names, axis=1))
    j = pd.DataFrame(np.sort(interactions, axis=1))
    
    k = j.groupby(j.columns.tolist())[0].count().reset_index(name='count')
    
    df = i.merge(k, on=[0, 1], how='left')\
          .fillna(0)\
          .rename(columns={0 : 'id_a', 1 : 'id_b'})
    df.iloc[:, :2] = names.values
    
    df
    
       id_a   id_b  count
    0   ben   jack    0.0
    1   ben   jack    0.0
    2  amir   jill    2.0
    3  jill  wilma    1.0
    4  amir  wilma    0.0
    
        2
  •  1
  •   mm441    7 年前

    抱歉,这是一个有点丑陋,我如何添加新的专栏等,但你可以得到的想法,并改善它。。。 首先,我假设名称中的所有对都是唯一的。所以我给每一对都一个ID

    names_ids = pd.DataFrame(pd.concat([names.iloc[:, 0] + '-' + names.iloc[:, 1],
                             names.iloc[:, 1] + '-' + names.iloc[:, 0]], 
                                       axis=0), 
                             columns=['pair'])
    names_ids['id'] = names_ids.index
    names_ids.index = names_ids.pair
    

    然后我将这些ID和交互连接起来,在交互中再次翻转每对ID

    interactions_new = pd.DataFrame(pd.concat([interactions.iloc[:, 0] + '-' + interactions.iloc[:, 1],
                                   interactions.iloc[:, 1] + '-' + interactions.iloc[:, 0]],
                                              axis=0),
                                    columns=['pair'])
    interactions_new['count'] = np.ones(len(interactions_new))
    
    count_id = interactions_new.join(names_ids['id'], on='pair', how='left').groupby('id').count().loc[:, ['count']]
    count_id['id'] = count_id.index
    

    因此,最后我只需计算交互中的每个id:

    names_ids.index = names_ids.id
    result = count_id.join(names_ids.pair.iloc[:len(names_ids)/2], on='id', how='left')
    result['count'] /= 2
    print result
    

    丑陋但没有循环,我得到:

         count   id        pair
    id                         
    2.0      2  2.0   jill-amir
    3.0      1  3.0  wilma-jill