在 Python 中对 pandas 中的数据框进行分箱 [重复]
Posted
技术标签:
【中文标题】在 Python 中对 pandas 中的数据框进行分箱 [重复]【英文标题】:binning a dataframe in pandas in Python [duplicate] 【发布时间】:2013-06-01 14:10:21 【问题描述】:鉴于 pandas 中的以下数据框:
import numpy as np
df = pandas.DataFrame("a": np.random.random(100), "b": np.random.random(100), "id": np.arange(100))
其中id
是由a
和b
值组成的每个点的ID,我如何将a
和b
分箱到一组指定的箱中(这样我就可以将a
和 b
在每个 bin 中的中值/平均值)?对于df
中的任何给定行,df
可能具有a
或b
(或两者)的NaN
值。
这是一个使用 Joe Kington 的解决方案的更好的示例,它具有更真实的df
。我不确定的是如何访问下面每个df.a
组的df.b
元素:
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?
# ...
【问题讨论】:
【参考方案1】:可能有更有效的方法(我觉得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
【讨论】:
优秀优雅!正是我想要的。根本不需要对数据框进行排序。 如果您想根据组访问b
值怎么办? groups.mean()
为您提供了仅a
的方法,我相信。
@user248237dfsf - 不,它给出了a
和b
的平均值(或者更确切地说,它给出了b
的平均值,由a
中的值组合而成,这就是我以为你在问)。
groups.mean()
返回一个DataFrame
,因此您可以通过groups.mean()["b"]
访问由a
分箱的b
的方法。【参考方案2】:
不是 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
当然,我不知道你想到了什么垃圾箱,所以你必须根据你的情况换掉我的垃圾箱。
【讨论】:
不错!我假设 OP 想用“a”来组合“b”,但回想起来,你的答案可能就是他们想要的。我会留下我的,因为我们的答案略有不同。 或许值得一提的是pandas.Dataframe(..)
和a_bins.agg([numpy.mean,numpy.median])
【参考方案3】:
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。
我知道对于这个特定问题来说这是一个挑剔的点,但对于我试图解决的类似问题,获得正确答案至关重要。
【讨论】:
【参考方案4】:如果你不必坚持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))
【讨论】:
以上是关于在 Python 中对 pandas 中的数据框进行分箱 [重复]的主要内容,如果未能解决你的问题,请参考以下文章
如何在 FOR 循环中对 Python Pandas 列表中的元素执行字符串更改
在 pandas / python 中对条件值进行分组和计数
在 Pandas 中对包含 Python `range` 或类似列表的列执行合并