首页 > 解决方案 > 通过比较相同行是否出现在数据框中的不同组中并分配相对值,在数据框中创建新列

问题描述

我有一个看起来像这样的 DataFrame(但是 149110 行):

df = {'group':['a','a','a','a',
                 'b','b','b','b','b','b','b','b','b',
                 'c','c','c','c','c',
                 'd','d','d','d','d','d','d',
                'e','e','e','e',],
        'date':[np.datetime64('2020-01-01'),np.datetime64('2020-01-01'),np.datetime64('2020-01-01'),np.datetime64('2020-01-01'),
                np.datetime64('2019-03-12'),np.datetime64('2019-03-12'),np.datetime64('2019-03-12'),np.datetime64('2019-03-12'),
                np.datetime64('2019-03-12'),np.datetime64('2019-03-12'),np.datetime64('2019-03-12'),np.datetime64('2019-03-12'),
                np.datetime64('2019-03-12'),
                np.datetime64('2020-01-01'),np.datetime64('2020-01-01'),np.datetime64('2020-01-01'),np.datetime64('2020-01-01'),
                np.datetime64('2020-01-01'),
                np.datetime64('2019-01-17'),np.datetime64('2019-01-17'),np.datetime64('2019-01-17'),np.datetime64('2019-01-17'),
                np.datetime64('2019-01-17'),np.datetime64('2019-01-17'),np.datetime64('2019-01-17'),
                np.datetime64('2018-12-03'),np.datetime64('2018-12-03'),np.datetime64('2018-12-03'),np.datetime64('2018-12-03')],
        'id':['tom','taliha','alyssa','randyl',
              'tom','taliha','edward','aaron','daniel','jean','sigmund','albus','riddle',
              'fellicia','ron','fred','george','alex',
              'taliha','alyssa','locke','jon','jamie','sam','sydney',
              'jon','jamie','sam','arya'],
        'value':[1,2,3,4,
                7,6,4,8,2,3,5,9,1,
                1,2,3,4,5,
                5,7,6,3,4,1,2,
                3,2,1,4]}
df= pd.DataFrame(df)
df

    group   date    id  value
0   a   2020-01-01  tom     1
1   a   2020-01-01  taliha  2
2   a   2020-01-01  alyssa  3
3   a   2020-01-01  randyl  4
4   b   2019-03-12  tom     7
5   b   2019-03-12  taliha  6
6   b   2019-03-12  edward  4
7   b   2019-03-12  aaron   8
8   b   2019-03-12  daniel  2
9   b   2019-03-12  jean    3
10  b   2019-03-12  sigmund 5
11  b   2019-03-12  albus   9
12  b   2019-03-12  riddle  1
13  c   2020-01-01  fellicia1
14  c   2020-01-01  ron     2
15  c   2020-01-01  fred    3
16  c   2020-01-01  george  4
17  c   2020-01-01  alex    5
18  d   2019-01-17  taliha  5
19  d   2019-01-17  alyssa  7
20  d   2019-01-17  locke   6
21  d   2019-01-17  jon     3
22  d   2019-01-17  jamie   4
23  d   2019-01-17  sam     1
24  d   2019-01-17  sydney  2
25  e   2018-12-03  jon     3
26  e   2018-12-03  jamie   2
27  e   2018-12-03  sam     1
28  e   2018-12-03  arya    4

我需要一个列:together如果该人与当前组中的另一个人在一个组中但在过去一年中,则返回 1。

例如,在“a”组中,我们有 4 个人,但 tom 和 taliha 都在一个组中,np.datetime64('2016-03-12')即他们都在“b”组中。我们还可以看到,在“c”组中,taliha 和 alyssa 也在一起。因此,我希望 a 组的相应值together在 tom、taliha 和 alyssa 旁边都有一个 1,但 randyl 为 0,因为他在过去一年中没有和其他任何人一起参加过。

然后对于组“b”和“c”,因为在过去一年中没有人与其他任何人在一个组中,我希望together每个人的值都为 0。

对于去年的“d”组,我们可以看到 jon、jamie 和 sam 在同一个组中,即他们是“e”组的一部分。所以together'd'组中 jon、jamie 和 sam 的值应该是 1,其余人的值应该是 0。

并且由于在“e”组之前没有数据,因此应该将它们都分配为 0。

然后我想创建另一个新列:rel基于此,取决于人们在前一个组中的价值。如果过去组中的那个人的值低于另一个人,我想rel等于 1,如果他们的值更高,我想等于 -1。

例如,在“a”组中,relfor tom 的值应该是 -1,因为他value在“b”中的值比 taliha高,因此relfor taliha 的值应该是 1,因为她在“b”中的值低于valuetom '。对于 alyssa,我希望将 的值rel设置为 -1,因为在 d 组中,她的值value高于 talhia。

基本上想法是value越低越好。我正在尝试按人们的过去对他们进行排名value。因此,对于“a”组,我需要一个基本上显示 taliha > tom 和 taliha > alyssa 的系统。但我们不知道 tom 和 alyssa 之间的关系,所以我将它们视为相同的值。我也不知道 randyl 和“a”组中的其他人之间的关系,所以我希望rel他的值设置为 0。例如,如果我发现这样的关系:人 1 > 人 2 > 人 3 并且没有人 4 的历史记录。我想rel反映他的关系。我希望 的值rel看起来有点像这个人 1 = 2、人 2 = 0、人 3 = -2 和人 4 = 0。

所以我希望生成的 DataFrame 看起来像这样:

    group   date    id  value   together    rel
0   a   2020-01-01  tom     1   1           -1
1   a   2020-01-01  taliha  2   1           1
2   a   2020-01-01  alyssa  3   1           -1
3   a   2020-01-01  randyl  4   0           0
4   b   2019-03-12  tom     7   0           0
5   b   2019-03-12  taliha  6   0           0
6   b   2019-03-12  edward  4   0           0
7   b   2019-03-12  aaron   8   0           0
8   b   2019-03-12  daniel  2   0           0
9   b   2019-03-12  jean    3   0           0
10  b   2019-03-12  sigmund 5   0           0
11  b   2019-03-12  albus   9   0           0
12  b   2019-03-12  riddle  1   0           0
13  c   2020-01-01  fellicia1   0           0
14  c   2020-01-01  ron     2   0           0
15  c   2020-01-01  fred    3   0           0
16  c   2020-01-01  george  4   0           0
17  c   2020-01-01  alex    5   0           0
18  d   2019-01-17  taliha  5   0           0
19  d   2019-01-17  alyssa  7   0           0
20  d   2019-01-17  locke   6   0           0
21  d   2019-01-17  jon     3   1           -2
22  d   2019-01-17  jamie   4   1           0
23  d   2019-01-17  sam     1   1           2
24  d   2019-01-17  sydney  2   0           0
25  e   2018-12-03  jon     3   0           0
26  e   2018-12-03  jamie   2   0           0
27  e   2018-12-03  sam     1   0           0
28  e   2018-12-03  arya    4   0           0

标签: pythonpandaspandas-groupby

解决方案


我会试一试。第一个任务似乎很简单,第二个让我很头疼。我对第二部分的结果与您的预期略有不同。也许你犯了一个错误,但很可能是由于我的误解。

from itertools import combinations

df_grps = df.groupby([df.date.dt.year, 'group']).id.apply(set)
df_vals = df.set_index([df.date.dt.year, 'group', 'id']).value
results = {}
for year in sorted(df.date.dt.year.unique())[1:]:
    groups = {}
    for group in df_grps.loc[year].index:
        ids = df_grps.loc[year, group]
        together = set().union(*(
                       i for i in (ids & h for h in df_grps.loc[year-1]) if len(i) > 1
                   ))
        if not together:
            continue
        together = {i: 0 for i in together}
        for i, j in combinations(together, 2):
            for group_old in df_grps.loc[year-1].index:
                if not {i, j} <= df_grps.at[year-1, group_old]:
                    continue
                i_val = df_vals.at[year-1, group_old, i]
                j_val = df_vals.at[year-1, group_old, j]
                if i_val < j_val:
                    together[i] += 1
                    together[j] -= 1
                elif i_val > j_val:
                    together[i] -= 1
                    together[j] += 1       
        groups[group] = together
    if groups:
        results[year] = groups

df_res = pd.DataFrame(
             [
                 [year, group, i, r]
                 for year, groups in results.items()
                 for group, rel in groups.items()
                 for i, r in rel.items()
             ],
             columns=['date', 'group', 'id', 'rel']
         ).set_index(['date', 'group', 'id'])

df.set_index([df.date.dt.year, 'group', 'id'], inplace=True)
df['together'], df['rel'] = 0, 0
df.loc[df_res.index, 'together'] = 1
df.loc[df_res.index, 'rel'] = df_res.rel

您的示例框架的结果:

                          date  value  together  rel
date group id                                       
2020 a     tom      2020-01-01      1         1   -1
           taliha   2020-01-01      2         1    2
           alyssa   2020-01-01      3         1   -1
           randyl   2020-01-01      4         0    0
2019 b     tom      2019-03-12      7         0    0
           taliha   2019-03-12      6         0    0
           edward   2019-03-12      4         0    0
           aaron    2019-03-12      8         0    0
           daniel   2019-03-12      2         0    0
           jean     2019-03-12      3         0    0
           sigmund  2019-03-12      5         0    0
           albus    2019-03-12      9         0    0
           riddle   2019-03-12      1         0    0
2020 c     fellicia 2020-01-01      1         0    0
           ron      2020-01-01      2         0    0
           fred     2020-01-01      3         0    0
           george   2020-01-01      4         0    0
           alex     2020-01-01      5         0    0
2019 d     taliha   2019-01-17      5         0    0
           alyssa   2019-01-17      7         0    0
           locke    2019-01-17      6         0    0
           jon      2019-01-17      3         1   -2
           jamie    2019-01-17      4         1    0
           sam      2019-01-17      1         1    2
           sydney   2019-01-17      2         0    0
2018 e     jon      2018-12-03      3         0    0
           jamie    2018-12-03      2         0    0
           sam      2018-12-03      1         0    0
           arya     2018-12-03      4         0    0

PS:我还有一个版本更多地保留在 Pandas 框架内,但它更长。如果您有兴趣,我会发布它。


推荐阅读