如何将组数映射到熊猫中的另一个数据框

时间:2021-02-23 20:17:03

标签: python pandas pandas-groupby

我有 2 个数据框,如下所示:

df1 = pd.DataFrame({'A': ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'],
                    'B': ['C1', 'C1', 'C1', 'C2', 'C2', 'C2', 'C2', 'C2'],
                    'rank': [2, 5, 1, 8, 6, 3, 4, 7]})

Out[3]: 
   A   B  rank
0  A  C1     2
1  B  C1     5
2  C  C1     1
3  D  C2     8
4  E  C2     6
5  F  C2     3
6  G  C2     4
7  H  C2     7

df2 = pd.DataFrame({'B': ['C1', 'C1', 'C1', 'C2'],
                    'C': [1, 2, 3, 4]})

Out[6]: 
    B  C
0  C1  1
1  C1  2
2  C1  3
3  C2  4

我想选择 df1 中排名最高的 3 个行(按“排名”列),但每组(B 列)最多只能选择 4 个名称,这需要包括每组中的行数df2.

生成的数据框应如下所示:

   A   B  rank
2  C  C1     1
5  F  C2     3
6  G  C2     4

逻辑:

组 C1 的 df2 中的行数为 3(在 df1 中从该组中最多再留下 1 行可供选择),C2 的数量为 1(从 df1 中最多留下 3 行可供选择)

项目C的排名最高,因此被选中,现在C1组的总数为4 F 项和 G 项排在第二位,属于 C2 组,总数为 3,因此小于 4

我尝试了以下方法:

df1.sort_values('rank').groupby('B').head(4).head(5)

但这限制在 B 中最多选择 4 行组,只选择 df1 中的行并忽略 df2

2 个答案:

答案 0 :(得分:1)

这是一个想法:

max_per_group = 4

# maximal rows to pick from each group
max_sizes = max_per_group - df2.groupby('B').size()

# 4 rows from each group
heads = df1.sort_values('rank').groupby('B').head(max_per_group)

# enumerate the rows within each group
enum = heads.groupby('B').cumcount()

# output
heads[enum<heads['B'].map(sizes).fillna(max_per_group)].head(3)

输出:

   A   B  rank
2  C  C1     1
5  F  C2     3
6  G  C2     4

答案 1 :(得分:1)

首先按组找出剩余的数量:

In [5]: (
   ...:     df1.sort_values('rank').groupby('B').apply(
   ...:         lambda x: x.sort_values('rank').head(remaining.get(x.name, 4))
   ...:     ).sort_values('rank').iloc[:3].reset_index('B', drop=True)
   ...: )
Out[5]:
   A   B  rank
2  C  C1     1
5  F  C2     3
6  G  C2     4

然后,从 groupby 中每个排序的组中选择该数字:

>>> import subprocess
>>> command = "echo 123"  # your command here.
>>> result = subprocess.run(command, text=True, shell=True, check=True, capture_output=True)
>>> user = 'unknown'
>>> print (user)
unknown
>>> if result.returncode == 0:
...     user = result.stdout.strip()
... 
>>> print (user)
123
>>>