将组 ID 返回到 pandas 数据帧

Posted

技术标签:

【中文标题】将组 ID 返回到 pandas 数据帧【英文标题】:Get group id back into pandas dataframe 【发布时间】:2013-02-10 22:20:00 【问题描述】:

对于数据框

In [2]: df = pd.DataFrame('Name': ['foo', 'bar'] * 3,
   ...:                    'Rank': np.random.randint(0,3,6),
   ...:                    'Val': np.random.rand(6))
   ...: df
Out[2]: 
  Name  Rank       Val
0  foo     0  0.299397
1  bar     0  0.909228
2  foo     0  0.517700
3  bar     0  0.929863
4  foo     1  0.209324
5  bar     2  0.381515

我有兴趣按名称和排名进行分组,并可能获取汇总值

In [3]: group = df.groupby(['Name', 'Rank'])
In [4]: agg = group.agg(sum)
In [5]: agg
Out[5]: 
                Val
Name Rank          
bar  0     1.839091
     2     0.381515
foo  0     0.817097
     1     0.209324

但我想在原始 df 中获取一个字段,其中包含该行的组号,例如

In [13]: df['Group_id'] = [2, 0, 2, 0, 3, 1]
In [14]: df
Out[14]: 
  Name  Rank       Val  Group_id
0  foo     0  0.299397         2
1  bar     0  0.909228         0
2  foo     0  0.517700         2
3  bar     0  0.929863         0
4  foo     1  0.209324         3
5  bar     2  0.381515         1

在 pandas 中有没有好的方法来做到这一点?

我可以用python得到它,

In [16]: from itertools import count
In [17]: c = count()
In [22]: group.transform(lambda x: c.next())
Out[22]: 
   Val
0    2
1    0
2    2
3    0
4    3
5    1

但它在大型数据帧上相当慢,所以我认为可能有更好的内置 pandas 方式来做到这一点。

【问题讨论】:

【参考方案1】:

使用来自 pandas 0.20.2+ 的 GroupBy.ngroup

df["GroupId"] = df.groupby(["Name", "Rank"]).ngroup()
print (df)
  Name  Rank       Val  GroupId
0  foo     2  0.451724        4
1  bar     0  0.944676        0
2  foo     0  0.822390        2
3  bar     2  0.063603        1
4  foo     1  0.938892        3
5  bar     2  0.332454        1

【讨论】:

【参考方案2】:

正确的解决方法是使用grouper.label_info

df["GroupId"] = df.groupby(["Name", "Rank"]).grouper.label_info

它会自动将df 数据框中的每一行与相应的组标签相关联。

【讨论】:

这之前有效,但 label_info 似乎已在 pandas 1.0 中删除【参考方案3】:

DataFrameGroupBy.grouper 对象中存储了很多方便的东西。例如:

>>> df = pd.DataFrame('Name': ['foo', 'bar'] * 3,
                   'Rank': np.random.randint(0,3,6),
                   'Val': np.random.rand(6))
>>> grouped = df.groupby(["Name", "Rank"])
>>> grouped.grouper.
grouped.grouper.agg_series        grouped.grouper.indices
grouped.grouper.aggregate         grouped.grouper.labels
grouped.grouper.apply             grouped.grouper.levels
grouped.grouper.axis              grouped.grouper.names
grouped.grouper.compressed        grouped.grouper.ngroups
grouped.grouper.get_group_levels  grouped.grouper.nkeys
grouped.grouper.get_iterator      grouped.grouper.result_index
grouped.grouper.group_info        grouped.grouper.shape
grouped.grouper.group_keys        grouped.grouper.size
grouped.grouper.groupings         grouped.grouper.sort
grouped.grouper.groups            

等等:

>>> df["GroupId"] = df.groupby(["Name", "Rank"]).grouper.group_info[0]
>>> df
  Name  Rank       Val  GroupId
0  foo     0  0.302482        2
1  bar     0  0.375193        0
2  foo     2  0.965763        4
3  bar     2  0.166417        1
4  foo     1  0.495124        3
5  bar     2  0.728776        1

grouper.group_info[0] 可能有一个更好的别名潜伏在某个地方,但无论如何这应该可以工作。

【讨论】:

另一个别名好像是grouped.grouper.labels[0] 唯一的问题是石斑鱼没有记录,不保证它不会破裂。 三年后,这件事仍然没有记录。但是很容易发现df.grouperBaseGrouper 类。 group_info 方法在代码中定义为 here,您可以进一步追溯以确认以下内容:1) group_info[1] 是唯一组标识符的数组,2) 行 @ 的组标识符987654332@是group_info[0][i],3)group_info[3]是组数 也许这是我对 python 的天真,但我很惊讶没有一个简单的、记录在案的方法。我提出这个问题是因为我想使用sklearn.cross_validation.StratifiedShuffleSplit 并在几个不同列的独特组合中进行分层。这个组 ID 正是我完成这项工作所需的单列,但很难找到。我很想知道这是否是对熊猫的滥用。 @jflournoy:巧合的是,我现在有一个 PR,可以通过规范的方式访问这些信息。

以上是关于将组 ID 返回到 pandas 数据帧的主要内容,如果未能解决你的问题,请参考以下文章

如何从 for 循环返回多个具有唯一名称的 pandas 数据帧?

如何将 Spark 数据帧转换为 Pandas 并返回 Kedro?

如何在 Pyspark 中使用 @pandas_udf 返回多个数据帧?

如果匹配,如何合并两个数据帧并从新列中的另一列返回数据?

有效地附加到 pandas 数据帧

强制 pandas .iloc 返回单行数据框?