将 Pandas GroupBy 多索引输出从 Series 转换回 DataFrame

2024-12-18 08:38:00
admin
原创
157
摘要:问题描述:我有一个数据框: City Name 0 Seattle Alice 1 Seattle Bob 2 Portland Mallory 3 Seattle Mallory 4 Seattle Bob 5 Portland Mallory...

问题描述:

我有一个数据框:

   City     Name
0   Seattle    Alice
1   Seattle      Bob
2  Portland  Mallory
3   Seattle  Mallory
4   Seattle      Bob
5  Portland  Mallory

我进行以下分组:

g1 = df1.groupby(["Name", "City"]).count()

打印出来是这样的:

                  City  Name
Name    City
Alice   Seattle      1     1
Bob     Seattle      2     2
Mallory Portland     2     2
        Seattle      1     1

但我最终想要的是另一个包含 GroupBy 对象中所有行的 DataFrame 对象。换句话说,我希望得到以下结果:

                  City  Name
Name    City
Alice   Seattle      1     1
Bob     Seattle      2     2
Mallory Portland     2     2
Mallory Seattle      1     1

我该怎么做?


解决方案 1:

g1一个 DataFrame。但它有一个分层索引:

In [19]: type(g1)
Out[19]: pandas.core.frame.DataFrame

In [20]: g1.index
Out[20]: 
MultiIndex([('Alice', 'Seattle'), ('Bob', 'Seattle'), ('Mallory', 'Portland'),
       ('Mallory', 'Seattle')], dtype=object)

也许你想要这样的东西?

In [21]: g1.add_suffix('_Count').reset_index()
Out[21]: 
      Name      City  City_Count  Name_Count
0    Alice   Seattle           1           1
1      Bob   Seattle           2           2
2  Mallory  Portland           2           2
3  Mallory   Seattle           1           1

或者类似这样:

In [36]: DataFrame({'count' : df1.groupby( [ "Name", "City"] ).size()}).reset_index()
Out[36]: 
      Name      City  count
0    Alice   Seattle      1
1      Bob   Seattle      2
2  Mallory  Portland      2
3  Mallory   Seattle      1

解决方案 2:

我想稍微改变一下Wes给出的答案,因为0.16.2版本需要as_index=False。如果不设置,则会得到一个空的数据框。

来源:

如果聚合函数将要聚合的组命名为列(as_index=True默认情况下为),则聚合函数不会返回这些组。分组的列将是返回对象的索引。

如果它们被命名为列,则传递as_index=False将返回您正在聚合的组。

聚合函数可以减少返回对象的维度,例如:meansumsizecountstdvar,,,,, 。例如sem,当您执行并返回时,就会发生这种情况。describe`firstlastnthminmaxDataFrame.sum()Series`

nth 可以充当减速器或过滤器,请参见此处。

import pandas as pd

df1 = pd.DataFrame({"Name":["Alice", "Bob", "Mallory", "Mallory", "Bob" , "Mallory"],
                    "City":["Seattle","Seattle","Portland","Seattle","Seattle","Portland"]})
print df1
#
#       City     Name
#0   Seattle    Alice
#1   Seattle      Bob
#2  Portland  Mallory
#3   Seattle  Mallory
#4   Seattle      Bob
#5  Portland  Mallory
#
g1 = df1.groupby(["Name", "City"], as_index=False).count()
print g1
#
#                  City  Name
#Name    City
#Alice   Seattle      1     1
#Bob     Seattle      2     2
#Mallory Portland     2     2
#        Seattle      1     1
#

编辑:

在版本及更高版本中,0.17.1您可以使用subsetincountreset_indexwith 参数:name`size`

print df1.groupby(["Name", "City"], as_index=False ).count()
#IndexError: list index out of range

print df1.groupby(["Name", "City"]).count()
#Empty DataFrame
#Columns: []
#Index: [(Alice, Seattle), (Bob, Seattle), (Mallory, Portland), (Mallory, Seattle)]

print df1.groupby(["Name", "City"])[['Name','City']].count()
#                  Name  City
#Name    City                
#Alice   Seattle      1     1
#Bob     Seattle      2     2
#Mallory Portland     2     2
#        Seattle      1     1

print df1.groupby(["Name", "City"]).size().reset_index(name='count')
#      Name      City  count
#0    Alice   Seattle      1
#1      Bob   Seattle      2
#2  Mallory  Portland      2
#3  Mallory   Seattle      1

count和之间的区别size在于size计算 NaN 值,而count不计算。

解决方案 3:

关键是使用reset_index()方法。

使用:

import pandas

df1 = pandas.DataFrame( { 
    "Name" : ["Alice", "Bob", "Mallory", "Mallory", "Bob" , "Mallory"] , 
    "City" : ["Seattle", "Seattle", "Portland", "Seattle", "Seattle", "Portland"] } )

g1 = df1.groupby( [ "Name", "City"] ).count().reset_index()

现在,您在g1中有了新的数据框:

结果数据框

解决方案 4:

简单地说,这应该可以完成任务:

import pandas as pd

grouped_df = df1.groupby( [ "Name", "City"] )

pd.DataFrame(grouped_df.size().reset_index(name = "Group_Count"))

这里,grouped_df.size()提取唯一的 groupby 计数,reset_index()方法重置您想要的列的名称。最后,Dataframe()调用 pandas 函数来创建 DataFrame 对象。

解决方案 5:

也许我误解了这个问题,但如果您想将 groupby 转换回数据框,则可以使用 .to_frame()。执行此操作时我想重置索引,因此我也包含了该部分。

与问题无关的示例代码

df = df['TIME'].groupby(df['Name']).min()
df = df.to_frame()
df = df.reset_index(level=['Name',"TIME"])

解决方案 6:

我发现这对我有用。

import numpy as np
import pandas as pd

df1 = pd.DataFrame({ 
    "Name" : ["Alice", "Bob", "Mallory", "Mallory", "Bob" , "Mallory"] , 
    "City" : ["Seattle", "Seattle", "Portland", "Seattle", "Seattle", "Portland"]})

df1['City_count'] = 1
df1['Name_count'] = 1

df1.groupby(['Name', 'City'], as_index=False).count()

解决方案 7:

下面的解决方案可能更简单:

df1.reset_index().groupby( [ "Name", "City"],as_index=False ).count()

解决方案 8:

这将以与 vanilla 方法相同的顺序返回序数级别/索引groupby()。它与 @NehalJWani 在其评论中发布的答案基本相同,但存储在一个变量中,并reset_index()调用该方法。

fare_class = df.groupby(['Satisfaction Rating','Fare Class']).size().to_frame(name = 'Count')
fare_class.reset_index()

此版本不仅返回对统计有用的相同数据(百分比),而且还包含 lambda 函数。

fare_class_percent = df.groupby(['Satisfaction Rating', 'Fare Class']).size().to_frame(name = 'Percentage')
fare_class_percent.transform(lambda x: 100 * x/x.sum()).reset_index()

      Satisfaction Rating      Fare Class  Percentage
0            Dissatisfied        Business   14.624269
1            Dissatisfied         Economy   36.469048
2               Satisfied        Business    5.460425
3               Satisfied         Economy   33.235294

例子:
在此处输入图片描述

解决方案 9:

我已经汇总了数量数据并存储到数据框

almo_grp_data = pd.DataFrame({'Qty_cnt' :
almo_slt_models_data.groupby( ['orderDate','Item','State Abv']
          )['Qty'].sum()}).reset_index()

解决方案 10:

这些解决方案对我来说只是部分有效,因为我正在进行多个聚合。以下是我想要转换为数据框的分组输出示例:

分组输出

因为我想要的不仅仅是 reset_index() 提供的计数,所以我编写了一个手动方法将上面的图像转换为数据框。我知道这不是最符合 Python/Pandas 的做法,因为它非常冗长和明确,但这就是我所需要的。基本上,使用上面解释的 reset_index() 方法启动一个“脚手架”数据框,然后循环遍历分组数据框中的组配对,检索索引,针对未分组数据框执行计算,并在新的聚合数据框中设置值。

df_grouped = df[['Salary Basis', 'Job Title', 'Hourly Rate', 'Male Count', 'Female Count']]
df_grouped = df_grouped.groupby(['Salary Basis', 'Job Title'], as_index=False)

# Grouped gives us the indices we want for each grouping
# We cannot convert a groupedby object back to a dataframe, so we need to do it manually
# Create a new dataframe to work against
df_aggregated = df_grouped.size().to_frame('Total Count').reset_index()
df_aggregated['Male Count'] = 0
df_aggregated['Female Count'] = 0
df_aggregated['Job Rate'] = 0

def manualAggregations(indices_array):
    temp_df = df.iloc[indices_array]
    return {
        'Male Count': temp_df['Male Count'].sum(),
        'Female Count': temp_df['Female Count'].sum(),
        'Job Rate': temp_df['Hourly Rate'].max()
    }

for name, group in df_grouped:
    ix = df_grouped.indices[name]
    calcDict = manualAggregations(ix)

    for key in calcDict:
        #Salary Basis, Job Title
        columns = list(name)
        df_aggregated.loc[(df_aggregated['Salary Basis'] == columns[0]) & 
                          (df_aggregated['Job Title'] == columns[1]), key] = calcDict[key]

如果您不喜欢使用字典,则可以在 for 循环中内联应用计算:

    df_aggregated['Male Count'].loc[(df_aggregated['Salary Basis'] == columns[0]) & 
                                (df_aggregated['Job Title'] == columns[1])] = df['Male Count'].iloc[ix].sum()

解决方案 11:

 grouped=df.groupby(['Team','Year'])['W'].count().reset_index()

 team_wins_df=pd.DataFrame(grouped)
 team_wins_df=team_wins_df.rename({'W':'Wins'},axis=1)
 team_wins_df['Wins']=team_wins_df['Wins'].astype(np.int32)
 team_wins_df.reset_index()
 print(team_wins_df)

解决方案 12:

尝试在group_by方法中设置group_keys=False,以防止将组键添加到索引中。

例子:

import numpy as np
import pandas as pd

df1 = pd.DataFrame({ 
    "Name" : ["Alice", "Bob", "Mallory", "Mallory", "Bob" , "Mallory"] , 
    "City" : ["Seattle", "Seattle", "Portland", "Seattle", "Seattle", "Portland"]})
df1.groupby(["Name"], group_keys=False)

解决方案 13:

.reset_index()方法/as_index=False参数

在大多数实际情况下,这两种变体的行为相同。事实上,如果我们查看groupby 的源代码,对于某些方法,as_index=False它实际上等同于reset_index()

# sample data
df = pd.DataFrame({
    'A': ['g1', 'g1', 'g2', 'g2'], 
    'B': [1, 1, 2, 2],
    'C': [1, 2, 3, 4]
})

y1 = df.groupby(['A', 'B'], as_index=False)['C'].sum()
y2 = df.groupby(['A', 'B'])['C'].sum().reset_index()
y1.equals(y2)   # True

最终,reset_index()进行以下转换(并且传递as_index=False完全避免了左侧的系列)。请注意,它创建了一个 3 列(分组列数 + 聚合列)数据框。

结果1

reset_index`as_index=False如果 grouper 中使用的列也出现在输出中(如 OP 中所示),则行为会有所不同。在这种情况下,从as_index=False`grouper 中删除所有重叠的列(通过_insert_inaxis_grouper方法)。以下示例说明了这一点。

df = pd.DataFrame({'A': ['g1', 'g1', 'g2', 'g2'], 'B': [1, 1, 2, 2]})

df.groupby(['A', 'B'])['B'].sum()                           # <--- includes B as a grouper
df.groupby(['A', 'B'])['B'].sum().reset_index(name='Total') # <--- includes B as a grouper
df.groupby(['A', 'B'], as_index=False)['B'].sum()           # <--- drops B from the grouper

不同情况

.to_frame()方法/groupby.method在列的列表中

to_frame()方法将 Series 转换为 DataFrame,其中 grouper 保留为索引,Series 中的值转换为 DataFrame 列。您可以选择为聚合列传递名称。但是,如果没有传递名称,则与简单地在 groupby 的列列表上调用聚合器函数完全相同。

x1 = df.groupby(['A', 'B'])['C'].sum().to_frame()
x2 = df.groupby(['A', 'B'])[['C']].sum()
#                          ^^   ^^  <--- list of columns
x1.equals(x2)   # True


# if `name=` is passed, it can rename the aggregated column in one go
x3 = df.groupby(['A', 'B'])['C'].sum().to_frame('Total')
x4 = df.groupby(['A', 'B'])[['C']].sum().rename(columns={'C': 'Total'})
x3.equals(x4)   # True

最终,to_frame(name)进行以下转换(并传递要聚合的列列表,完全避免左侧的系列)。请注意,与不同reset_index(),它创建单列数据框。

结果2


最后,至少从 pandas 0.16.2 开始,方法( OP 中的groupby.count特定方法)返回一个空的数据框。但是,通过在每个拆分上调用 count可以恢复聚合计数。正如 jezrael 的回答中提到的,列出所有聚合列也有效,但如果有很多列,这种情况可能更具可读性。groupby`groupby.agg`

df1 = pd.DataFrame({ 
    "Name": ["Alice", "Bob", "Mallory", "Mallory", "Bob" , "Mallory"], 
    "City": ["Seattle", "Seattle", "Portland", "Seattle", "Seattle", "Portland"]
})

df1.groupby(['Name', 'City']).count()                   # empty dataframe
df1.groupby(['Name', 'City']).agg(lambda x: x.count())  # OK

结果3

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用