【问题标题】:How to bin a 2D data along the x-axis with Python如何使用 Python 沿 x 轴分箱 2D 数据
【发布时间】:2018-11-11 09:55:37
【问题描述】:

我有两个对应的数据数组(x 和 y),我在对数图上绘制如上。数据目前过于精细,我想将它们分箱以获得更平滑的关系。我能否获得一些关于如何沿 x 轴以 exponential 分箱大小分箱的指导,使其在对数刻度上呈线性显示?

例如,如果第一个 bin 的范围为 x = 10^0 到 10^1,我想收集该范围内对应 x 的所有 y 值,并将它们平均为该 bin 的一个值。我不认为 np.hist 或 plt.hist 完全可以解决问题,因为它们通过计数出现来进行分箱。

编辑:对于上下文,如果有帮助,上面的图是一个分类图,它绘制了某个网络的进出度。

【问题讨论】:

    标签: python numpy matplotlib histogram binning


    【解决方案1】:

    您可以使用scipy.stats.binned_statistic 来获取每个 bin 中数据的平均值。最好通过numpy.logspace 创建垃圾箱。然后,您可以绘制这些方法,例如作为跨越 bin 宽度的水平线或分散在平均位置。

    import numpy as np; np.random.seed(42)
    from scipy.stats import binned_statistic
    import matplotlib.pyplot as plt
    
    x = np.logspace(0,5,300)
    y = np.logspace(0,5,300)+np.random.rand(300)*1.e3
    
    
    fig, ax = plt.subplots()
    ax.scatter(x,y, s=9)
    
    s, edges, _ = binned_statistic(x,y, statistic='mean', bins=np.logspace(0,5,6))
    
    ys = np.repeat(s,2)
    xs = np.repeat(edges,2)[1:-1]
    ax.hlines(s,edges[:-1],edges[1:], color="crimson", )
    
    for e in edges:
        ax.axvline(e, color="grey", linestyle="--")
    
    ax.scatter(edges[:-1]+np.diff(edges)/2, s, c="limegreen", zorder=3)
    
    ax.set_xscale("log")
    ax.set_yscale("log")
    plt.show()
    

    【讨论】:

    • 感谢您的回答!这几乎可以满足我的需要,除了我更喜欢绘制数据点而不是表示 bin 平均值的线。 y 个数据点已经在数组 s 中。为了获得可绘制的 x 数据点(每个 bin 的平均值),我做了for left_edge,right_edge in zip(edges,edges[1:]): x.append(np.mean([left_edge,right_edge])),其中x 被初始化为一个空列表。这通过取每个 bin 的两个边缘的平均值来计算每个 bin 的中心点。然后我plt.plot(x,s,'s')。我得到了我需要的东西!
    • 您可以使用ax.scatter(edges[:-1]+np.diff(edges)/2)。我更新了答案。
    【解决方案2】:

    您可以使用 pandas 来实现这一点。这个想法是使用np.digitize 将每个 X 值分配给一个区间。由于您使用的是对数刻度,因此使用 np.logspace 选择长度呈指数变化的间隔是有意义的。最后,您可以对每个区间中的 X 值进行分组并计算 Y 平均值。


    import pandas as pd
    import numpy as np
    
    x_max = 10
    
    xs = np.exp(x_max * np.random.rand(1000))
    ys = np.exp(np.random.rand(1000))
    
    df = pd.DataFrame({
        'X': xs,
        'Y': ys,
    })
    
    df['Xbins'] = np.digitize(df.X, np.logspace(0, x_max, 30, base=np.exp(1)))
    df['Ymean'] = df.groupby('Xbins').Y.transform('mean')
    df.plot(kind='scatter', x='X', y='Ymean')
    

    【讨论】:

    • Yakim,您的答案将大大受益于将 logx=True, logy=True 添加到 df.plot 命令。线性比例会产生一个看起来很奇怪的图。显示代码的输出也很好。
    • 谢谢!这可以按我的需要工作。您能否简要解释一下 groupby 步骤,代码在做什么?我正在尝试阅读 groupby 文档,但这很长而且很混乱。
    • groupby('Xbins') 遍历df 行的子集,在Xbins 列中具有相同的值。对于每个这样的子集,我们用Y.transform('mean') 计算Y 列的平均值。 transform 方法`只是意味着输出具有与原始 df 相同的形状。文档应涵盖applyagg 的替代应用程序。
    猜你喜欢
    • 1970-01-01
    • 2017-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-15
    • 2014-12-29
    • 2017-07-31
    • 2016-05-07
    相关资源
    最近更新 更多