创建numpy数组元素的五分位数

时间:2017-03-10 22:03:59

标签: python arrays numpy

我试图将numpy数组的每个元素替换为落入其五分位数的元素的平均值。这是我啰嗦的做法:创建存储不同五分之一边界值的标量(20,40,60,80和100百分位值,命名为q1到q5)。然后,创建每个五分位数内所有元素的平均值,并将它们命名为m1到m5。接下来,遍历numpy数组的每个元素并检查它落入哪个五分位数,并用对应于该五分位数的平均值替换它。我相信有一种使用布尔掩蔽的Pythonic方法,但不知道从哪里开始。请指教。

fgets

2 个答案:

答案 0 :(得分:2)

我不确定这是否是最狡猾的方式,但这是一个更简洁的方式

import numpy as np
np.random.seed(42)
aray = np.random.randn(10)

quintile_thres = [np.percentile(aray, i, interpolation='lower')
                  for i in range(0, 100+1, 20)]
# add -inf to front to keep consistency of
# (aray > q1) & (aray <= q2)
quintile_thres.insert(0, -np.inf)

aray_copy = aray.copy()
# for zip refer to https://docs.python.org/3/library/functions.html#zip
for q1, q2 in zip(quintile_thres[:-1], quintile_thres[1:]):
    aray[[(aray > q1) & (aray <= q2)]] = \
        aray_copy[(aray_copy > q1) & (aray_copy <= q2)].mean()

你可以避免复制课程......

答案 1 :(得分:2)

这是一种可以一次性计算分位数和均值的算法。不过,我不确定在所有情况下舍入将是100%。五分位数是使用reduceat ufunc的np.add方法计算的。

更新:实际上,argsort可以替换为argpartition,在大型数组上应该更快。

import numpy as np
np.random.seed(42)    
aray = np.random.randn(10)

boundaries = np.linspace(0, len(aray), 6, dtype = int)
#inds = np.argsort(aray)
inds = np.argpartition(aray, boundaries[1:-1])
means = np.add.reduceat(aray[inds], boundaries[:-1]) / np.diff(boundaries)
aray[inds] = np.repeat(means, np.diff(boundaries))

步骤一步

边界将是[0,2,4,6,8,10]我们扔掉0和10所以argpartition将分裂元素(按排名顺序)2,4,6,8。这在引用时产生5个分区by inds [:2],inds [2:4],inds [4:6],inds [6:8]和inds [8:]我们保证aray [inds [:2]]&lt; = aray [ inds [2]]&lt; = aray [inds [2:4]]&lt; = aray [inds [4]]等 np.add.reduceat返回切片的总和aray [inds] [0:2],aray [inds] [2:4],...,aray [inds] [8:],np.diff计算适当的分母。 np.repeat为每个五分位数中的每个元素创建均值的副本。