在 x 范围内对 y 值进行运行中位数计算

15

下面是我从两个numpy数组构造的散点图。

散点图示例 enter image description here

我想在这个图中添加一个沿x轴范围内y值的运行中位数。 我用Photoshop制作了一个示例:

修改后的散点图 enter image description here

具体来说,我需要在x轴范围内每个单位上的数据点的中位数(这个范围会因许多情节而异,但我可以手动调整)。 我感谢任何可以指引我正确方向的提示。


相邻箱中的 y 值集合之间是否存在依赖或相关性?除非存在,否则您必须在每个集合上应用标准中位数计算。 - collapsar
不,每个箱子都可以单独处理。为了计算图中的总体中位数,我在所有y值上使用了pylab.median。不幸的是,我不确定如何将值分成特定大小的箱子,覆盖x的范围。一旦我克服了这个障碍,我就可以在每个箱子上重复中位数计算。 - mjcowley
4个回答

12

我会使用np.digitize来为您进行分桶排序。这样,您可以轻松地应用任何函数,并设置您感兴趣的范围。

import numpy as np
import pylab as plt

N = 2000
total_bins = 10

# Sample data
X = np.random.random(size=N)*10
Y = X**2 + np.random.random(size=N)*X*10

bins = np.linspace(X.min(),X.max(), total_bins)
delta = bins[1]-bins[0]
idx  = np.digitize(X,bins)
running_median = [np.median(Y[idx==k]) for k in range(total_bins)]

plt.scatter(X,Y,color='k',alpha=.2,s=2)
plt.plot(bins-delta/2,running_median,'r--',lw=4,alpha=.8)
plt.axis('tight')
plt.show()

举一个这种方法多功能性的例子,我们可以添加每个区间标准差所表示的误差线:

enter image description here

running_std    = [Y[idx==k].std() for k in range(total_bins)]
plt.errorbar(bins-delta/2,running_median,
              running_std,fmt=None)

在此输入图片描述


太好了。谢谢你额外提供的一点内容! - mjcowley

5

这个问题也可以通过Python数据分析库pandas高效地解决,该库提供了本地数据切割和分析方法。

考虑以下示例:

(感谢@Hooked的示例,我从中借用了XY数据)

 import pandas as pd
 df = pd.DataFrame({'X' : X, 'Y' : Y})  #we build a dataframe from the data

 data_cut = pd.cut(df.X,bins)           #we cut the data following the bins
 grp = df.groupby(by = data_cut)        #we group the data by the cut

 ret = grp.aggregate(np.median)         #we produce an aggregate representation (median) of each bin

 #plotting

 plt.scatter(df.X,df.Y,color='k',alpha=.2,s=2)
 plt.plot(ret.X,ret.Y,'r--',lw=4,alpha=.8)
 plt.show()

注意:这里红色曲线的x值是按照每个区间的x中位数排列的(也可以使用区间的中点)。

enter image description here


1
很好的方法。我尝试了所有的建议,每个都非常有效。谢谢! - mjcowley

3
你可以基于 numpy.median() 创建一个函数,用于计算给定区间的中位数值:
import numpy as np

def medians(x, y, intervals):
    out = []
    for xmin, xmax in intervals:
        mask = (x >= xmin) & (x < xmax)
        out.append(np.median(y[mask]))
    return np.array(out)

然后在所需的间隔中使用此功能:

import matplotlib.pyplot as plt

intervals = ((18, 19), (19, 20), (20, 21), (21, 22))
centers = [(xmin+xmax)/2. for xmin, xmax in intervals]

plt.plot(centers, medians(x, y, intervals)

1
很好的方法。我尝试了所有建议,每一个都非常有效。谢谢! - mjcowley
1
如果间隔是连续的,您可以使用itertools pairwise配方:intervals = pairwise((18, 19, 20, 21, 22))pairwise(range(18, 23, 1)) - IceArdor

1

我用C#写了类似这样的东西。我不会Python,所以这里是伪代码:

  • 创建一个List用于数据,其中中位数将被派生出来
  • x值对散点图点进行排序
  • 通过x值循环遍历排序后的点
  • 对于每个点,将该点的Y值插入到中位数列表中,以便中位数列表作为已排序列表增长。即插入Y,使得它上面和下面的List值大于和小于它。在这里看一下:在Python中将值插入到特定位置的列表中
  • 在添加每个Y值之后,中位数值将是当前中间索引的列表值,即List(List.Length/2)

希望能帮到你!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接