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