46

给定熊猫中的以下数据框:

import numpy as np
df = pandas.DataFrame({"a": np.random.random(100), "b": np.random.random(100), "id": np.arange(100)})

每个id点的 id 由一个ab值组成,我如何分箱ab放入一组指定的箱(这样我就可以在每个箱中获取a和的中值/平均值b)?df可能有NaNab中的任何给定行df

这是一个使用 Joe Kington 的解决方案的更好的示例,它具有更现实的df. 我不确定的是如何访问下面df.b每个df.a组的元素:

a = np.random.random(20)
df = pandas.DataFrame({"a": a, "b": a + 10})
# bins for df.a
bins = np.linspace(0, 1, 10)
# bin df according to a
groups = df.groupby(np.digitize(df.a,bins))
# Get the mean of a in each group
print groups.mean()
## But how to get the mean of b for each group of a?
# ...
4

4 回答 4

63

可能有一种更有效的方法(我觉得pandas.crosstab在这里会很有用),但我会这样做:

import numpy as np
import pandas

df = pandas.DataFrame({"a": np.random.random(100),
                       "b": np.random.random(100),
                       "id": np.arange(100)})

# Bin the data frame by "a" with 10 bins...
bins = np.linspace(df.a.min(), df.a.max(), 10)
groups = df.groupby(np.digitize(df.a, bins))

# Get the mean of each bin:
print groups.mean() # Also could do "groups.aggregate(np.mean)"

# Similarly, the median:
print groups.median()

# Apply some arbitrary function to aggregate binned data
print groups.aggregate(lambda x: np.mean(x[x > 0.5]))

编辑:由于 OP 专门要求仅b通过 中的值进行分箱a,只需执行

groups.mean().b

此外,如果您希望索引看起来更好(例如,将间隔显示为索引),就像在@bdiamante 的示例中所做的那样,请使用pandas.cut而不是numpy.digitize. (向比达曼特致敬。我没有意识到pandas.cut存在。)

import numpy as np
import pandas

df = pandas.DataFrame({"a": np.random.random(100), 
                       "b": np.random.random(100) + 10})

# Bin the data frame by "a" with 10 bins...
bins = np.linspace(df.a.min(), df.a.max(), 10)
groups = df.groupby(pandas.cut(df.a, bins))

# Get the mean of b, binned by the values in a
print groups.mean().b

这导致:

a
(0.00186, 0.111]    10.421839
(0.111, 0.22]       10.427540
(0.22, 0.33]        10.538932
(0.33, 0.439]       10.445085
(0.439, 0.548]      10.313612
(0.548, 0.658]      10.319387
(0.658, 0.767]      10.367444
(0.767, 0.876]      10.469655
(0.876, 0.986]      10.571008
Name: b
于 2013-06-05T20:42:45.117 回答
27

不是 100% 确定这是否是您正在寻找的,但这是我认为您正在寻找的:

In [144]: df = DataFrame({"a": np.random.random(100), "b": np.random.random(100), "id":   np.arange(100)})

In [145]: bins = [0, .25, .5, .75, 1]

In [146]: a_bins = df.a.groupby(cut(df.a,bins))

In [147]: b_bins = df.b.groupby(cut(df.b,bins))

In [148]: a_bins.agg([mean,median])
Out[148]:
                 mean    median
a
(0, 0.25]    0.124173  0.114613
(0.25, 0.5]  0.367703  0.358866
(0.5, 0.75]  0.624251  0.626730
(0.75, 1]    0.875395  0.869843

In [149]: b_bins.agg([mean,median])
Out[149]:
                 mean    median
b
(0, 0.25]    0.147936  0.166900
(0.25, 0.5]  0.394918  0.386729
(0.5, 0.75]  0.636111  0.655247
(0.75, 1]    0.851227  0.838805

当然,我不知道您的想法是什么垃圾箱,因此您必须根据自己的情况换掉我的垃圾箱。

于 2013-06-05T20:42:58.407 回答
16

Joe Kington 的回答非常有帮助,但是,我注意到它并没有对所有数据进行分类。它实际上用 a = a.min() 省略了行。总结groups.size()给了 99 而不是 100。

为了保证所有数据都被分箱,只需将分箱数传递给 cut() ,该函数将自动将第一个[最后一个]分箱填充 0.1% 以确保包含所有数据。

df = pandas.DataFrame({"a": np.random.random(100), 
                    "b": np.random.random(100) + 10})

# Bin the data frame by "a" with 10 bins...
groups = df.groupby(pandas.cut(df.a, 10))

# Get the mean of b, binned by the values in a
print(groups.mean().b)

在这种情况下,将 groups.size() 相加得出 100。

我知道这是这个特定问题的一个挑剔点,但对于我试图解决的类似问题,获得正确答案至关重要。

于 2014-05-16T02:26:51.107 回答
2

如果您不必坚持pandas分组,您可以使用scipy.stats.binned_statistic

from scipy.stats import binned_statistic

means = binned_statistic(df.a, df.b, bins=np.linspace(min(df.a), max(df.a), 10))
于 2017-10-30T10:46:25.663 回答