【问题标题】:Creating a new column in Pandas based on another dataframe基于另一个数据框在 Pandas 中创建一个新列
【发布时间】:2017-12-20 18:17:05
【问题描述】:

我需要根据第二个数据框的属性向现有的 pandas 数据框添加一列。我做了一个最小的例子来说明我的确切要求。

我有两个数据框,一个代表姓名对,另一个代表两个人之间的交互:

    >>> 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'] AND names['id_b']interactions['individual1']interactions['individual2']。对于名称中的所有行,此计数需要包含在列 num_interactions 中,即使名称是重复的(即,如果有一行 id_a 是 ben 并且 id_b 是 jack 并且这些名称是颠倒的( id_a 是 jack,id_b 是 ben),这两行都应该包含 num_interactions)

生成的数据框如下所示:

>>> 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']})

提前致谢!

【问题讨论】:

  • 类似names['num_interactions'] = interactions.groupby(['individual1 ','individual2']).transform('count') ?
  • @LucasDresl 不幸的是,这无法处理成对之间的不同顺序。

标签: python pandas dataframe


【解决方案1】:

抱歉,我如何添加新列等有点难看,但您可以了解并改进它... 首先,我假设名称中的所有对都是唯一的。所以我给每一对都一个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 加入到交互中,在交互中我再次翻转每一对

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

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

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

【讨论】:

  • 酷,这是一种与我想象的不同的方法,但它很有效。唯一需要考虑的是,当您翻转对子时,计数最终会加倍(在我最初的示例中,jill-amir 的计数应该是 2,而 wilma-jill 的计数应该最终是 1,你的值是这个的两倍)
  • @sacul 已修复 :)
【解决方案2】:

假设顺序无关紧要,您可以按每个数据框的列对其进行排序。对于第二个数据帧,计算每组与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

【讨论】:

  • 谢谢!这很接近,但我应该更清楚:在名称、数据帧中,如果有“jack-ben”和“ben-jack”行,它们中的每一个都需要包含在内,所以我不能放弃重复和排序。我会在我原来的帖子中澄清。
  • @sacul 看到我的编辑了吗?我已经解决了这个问题……实际上很简单。
  • 是的,行得通!仍然试图以您的策略为基础,这样我就可以得到一个未修改 id_a 和 id_b 的数据框。
  • @sacul 如果您对某件事感到满意,请随时对我的答案进行编辑,并在您觉得您的问题已得到解答时按下接受按钮。祝你好运!
猜你喜欢
  • 2018-05-20
  • 1970-01-01
  • 1970-01-01
  • 2019-02-02
  • 1970-01-01
  • 2022-11-22
  • 2016-05-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多