Pandas groupby:计算(相对)大小并保存在原始数据帧中

时间:2014-04-22 09:15:45

标签: python pandas

我的数据库结构是这样的,我有单位,属于几个组,并有不同的变量(我专注于一个,X,对于这个问题)。然后我们有基于年份的记录。所以数据库看起来像

    unitid, groupid, year, X
0        1        1, 1990, 5
1        2        1, 1990, 2
2        2        1, 1991, 3
3        3        2, 1990, 10

等。现在我想做的是测量一些“强度”变量,即每组和每年的单位数量,我想把它重新放回数据库。

到目前为止,我正在做

asd = df.drop_duplicates(cols=['unitid', 'year'])
groups = asd.groupby(['year', 'groupid'])
intensity = groups.size()

然后强度看起来像

year groupid
1961    2000    4
        2030    3
        2040    1
        2221    1
        2300    2

但是,我不知道如何将它们放回旧的数据帧中。我可以通过intensity[0]访问它们,但intensity.loc()给出一个LocIndexer不可调用的错误。

其次,如果我可以扩展强度,那将是非常好的。而不是“每组每年的单位”,它将是“每组每年的单位,按当年每组的平均/最大单位换算”。如果{t,g}表示组年单元格,则为:

relative intensity

也就是说,如果我的简单强度变量(时间和组)被称为强度(t,g),我想创建relativeIntensity(t,g) = intensity(t,g)/mean(intensity(t=t,g=:)) - 如果这个假代码有助于使我自己清楚。

谢谢!

更新

为了便于阅读,请在此处(明确地)提供答案。第一部分由

解决
intensity = intensity.reset_index()
df['intensity'] = intensity[0]

2 个答案:

答案 0 :(得分:1)

这是a multi-index。您可以通过调用.reset_index()到结果数据帧来重置索引。或者,您可以在计算分组操作时将其禁用,方法是将as_index=False指定为groupby(),例如:

intensity = asd.groupby(["year", "groupid"], as_index=False).size()

关于你的第二个问题,我不确定你在Instead of "units per group-year", it would be "units per group-year, scaled by average/max units per group-year in that year".中的意思。如果您想通过intensity / mean(intensity)计算“强度”,可以使用transform方法,例如:

asd.groupby(["year", "groupid"])["X"].transform(lambda x: x/mean(x))

这是你要找的吗?

更新

如果您想计算intensity / mean(intensity),其中mean(intensity)仅基于year而非year/groupid子集,那么您首先必须创建mean(intensity) }仅基于year,例如:

intensity["mean_intensity_only_by_year"] = intensity.groupby(["year"])["X"].transform(mean)

然后为所有intensity / mean(intensity)子集计算year/groupid,其中mean(intensity)仅来自year子集:

intensity["relativeIntensity"] = intensity.groupby(["year", "groupid"]).apply(lambda x: pd.DataFrame(
                        {"relativeIntensity": x["X"] / x["mean_intensity_only_by_year"] }
                    ))

也许这就是你要找的,对吗?

答案 1 :(得分:1)

实际上,几天之后,我发现这个双重问题的第一个答案是错误的。也许有人可以详细说明.size()实际上做了什么,但这是为了万一有人用谷歌搜索这个问题并没有走错路。

事实证明,.size()的行数比原始对象少(如果我使用reset_index(),但是我尝试将大小堆叠回原始对象,有很多使用NaN留下的行。但是,以下内容可以使用

groups = asd.groupby(['year', 'groupid'])
intensity = groups.apply(lambda x: len(x))
asd.set_index(['year', 'groupid'], inplace=True)
asd['intensity'] = intensity

或者,可以做

groups = asd.groupby(['fyearq' , 'sic'])
# change index to save groupby-results
asd= asd.set_index(['fyearq', 'sic'])
asd['competition'] = groups.size()

我的问题的第二部分通过

回答
# relativeSize
def computeMeanInt(group):
    group = group.reset_index()
    # every group has exactly one weight in the mean:
    sectors = group.drop_duplicates(cols=['group'])
    n = len(sectors)
    val = sum(sectors.competition)
    return float(val) / n


result = asd.groupby(level=0).apply(computeMeanInt)
asd= asd.reset_index().set_index('fyearq')
asd['meanIntensity'] = result
# if you don't reset index, everything crashes (too intensive, bug, whatever)
asd.reset_index(inplace=True)
asd['relativeIntensity'] = asd['intensity']/asd['meanIntensity']