【问题标题】:binning a dataframe in pandas in Python [duplicate]在 Python 中对 pandas 中的数据框进行分箱 [重复]
【发布时间】: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 是由ab 值组成的每个点的ID,我如何将ab 分箱到一组指定的箱中(这样我就可以将ab 在每个 bin 中的中值/平均值)?对于df 中的任何给定行,df 可能具有ab(或两者)的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?
# ...

【问题讨论】:

    标签: python numpy pandas


    【解决方案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 - 不,它给出了ab 的平均值(或者更确切地说,它给出了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))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-19
        • 1970-01-01
        • 2021-12-06
        • 1970-01-01
        • 1970-01-01
        • 2017-12-29
        相关资源
        最近更新 更多