从平均计算中删除数组的max和min元素

时间:2017-11-16 05:39:59

标签: python arrays numpy max

我希望从数组3 * 4中删除最高数字和最低数字。比方说,数据看起来像这样:

a=np.array([[1,4,5,10],[2,6,5,0],[3,9,9,0]])

所以我希望看到这样的结果:     deleted_data = [4,5],[2,5],[3]

你能告诉我如何删除每个阵列的最大值和最小值吗?

这样做,我确实喜欢这个(更新):

#to find out the max / min values:
b = np.max(a,1) #max
c = np.min(a,1) #min

#creating dataset after deleting max & min
d=(a!=b[:,None]) & (a!=c[:,None]) 
f=[i[j] for i,j in zip(a, d)]

output: [array([8, 7, 7, 9, 9, 8]), array([8, 7, 8, 6, 8, 8]), array([9, 8, 9, 9, 8]), array([6, 7, 7, 6, 6, 7]), array([7, 7, 7, 7, 6])]

现在我不确定如何计算列表对象的平均值? 我想计算每个数组的平均值,所以我试过这个:

mean1=f.mean(axis=0)

但它不起作用。

5 个答案:

答案 0 :(得分:2)

另一种方法是使用Masked Array

import numpy.ma as ma

mask = np.logical_or(a == a.max(1, keepdims = 1), a == a.min(1, keepdims = 1))
a_masked = ma.masked_array(a, mask = mask)
如果你想要平均的非掩盖元素,你可以从那里

a_masked.mean()

或者你甚至可以做行的意思

a_masked.mean(1).data

或列(奇怪,但似乎是你要求的)

a_masked.mean(0).data

答案 1 :(得分:1)

python list有一个remove方法。

使用效用函数,我们可以从行中删除min和max元素:

def foo(i,j,k):
    il = i.tolist()
    il.remove(j)
    il.remove(k)
    return il

In [230]: [foo(i,j,k) for i,j,k in zip(a,b,c)]
Out[230]: [[4, 5], [2, 5], [3, 9]]

这可以转回到np.array(...)的数组中。请注意,这只删除了最后一行中的9之一。如果它已经删除了两个,则最后一个列表只有1个值,结果无法转回到2d数组。

我确信我们可以提出一种纯数组方法,可能使用argmaxargmin代替maxmin。但我认为列表方法对于Python初学者来说是一个更好的起点。

数组屏蔽方法

In [232]: bi = np.argmax(a,1)
In [233]: ci = np.argmin(a,1)
In [234]: bi
Out[234]: array([3, 1, 1], dtype=int32)
In [235]: ci
Out[235]: array([0, 3, 3], dtype=int32)

In [243]: mask = np.ones_like(a, bool)
In [244]: mask[np.arange(3),bi]=False
In [245]: mask[np.arange(3),ci]=False
In [246]: mask
Out[246]: 
array([[False,  True,  True, False],
       [ True, False,  True, False],
       [ True, False,  True, False]], dtype=bool)

In [247]: a[mask]
Out[247]: array([4, 5, 2, 5, 3, 9])
In [248]: _.reshape(3,-1)
Out[248]: 
array([[4, 5],
       [2, 5],
       [3, 9]])

如果我们只是从每一行删除一个最多和一分钟,这样做会更好。

另一种掩盖方法:

In [257]: (a!=b[:,None]) & (a!=c[:,None])
Out[257]: 
array([[False,  True,  True, False],
       [ True, False,  True, False],
       [ True, False, False, False]], dtype=bool)
In [258]: a[(a!=b[:,None]) & (a!=c[:,None])]
Out[258]: array([4, 5, 2, 5, 3])

这会删除最后一行中的所有	 9。但它不会保留行拆分。

这会保留行结构,并允许可变长度:

In [259]: mask=(a!=b[:,None]) & (a!=c[:,None])
In [260]: [i[j] for i,j in zip(a, mask)]
Out[260]: [array([4, 5]), array([2, 5]), array([3])]

答案 2 :(得分:1)

正如@hpaulj预测的那样,有一种仅限数组的方法。这是一个很糟糕的事情。作为一个单行:

a[np.arange(a.shape[0])[:, None], np.sort(np.argpartition(a, (0,-1), axis = 1)[:, 1:-1], axis = 1)]

让我们打破这一点:

y_ = np.argpartition(a, (0,-1), axis = 1)[:, 1:-1]

argpartiton获取每行的0(最小)和-1(最大)元素的索引,并将它们重新移动到第一个和最后一个位置。 [:,1:-1]为其他所有内容编制索引。现在argpartition有时可以重新排序其余元素,所以

y = np.sort(y_ , axis = 1)

我们将其余指数分类回原点位置。现在,我们为您的原始y.shape -> (m, n-2)数组添加了(m, n) = a.shape索引数组,其中删除了最大值和最小值。

现在使用它,我们也需要行指示。

x = np.arange(a.shape[0])[:, None]

arange只提供m行索引。要将此x.shape -> (a.shape[0],) -> (m,)数组广播到索引数组,您需要[:, None]来制作x.shape -> (m, 1)。现在m排队进行广播,你有两套索引。

a[x, y]

array([[4, 5],
       [2, 5],
       [3, 9]])

答案 3 :(得分:1)

您可以通过屏蔽的两个步骤到达每行不是maxmin的元素的平均最终目的地 -

In [140]: a  # input array
Out[140]: 
array([[ 1,  4,  5, 10],
       [ 2,  6,  5,  0],
       [ 3,  9,  9,  0]])

In [141]: m = (a!=a.min(1,keepdims=1)) & (a!=a.max(1,keepdims=1))

In [142]: (a*m).sum(1)/m.sum(1).astype(float)
Out[142]: array([ 4.5,  3.5,  3. ])

这避免了创建中间参差不齐的数组的麻烦,这些数组不是使用NumPy函数操作的最方便的数据格式。

或者,为了提升效果,请使用np.einsum来获得与(a*m).sum(1)同等的np.einsum('ij,ij->i',a,m)

更大阵列上的运行时测试 -

In [181]: np.random.seed(0)

In [182]: a = np.random.randint(0,10,(5000,5000))

# @Daniel F' soln from https://stackoverflow.com/a/47325431/
In [183]: %%timeit
     ...: mask = np.logical_or(a == a.max(1, keepdims = 1), a == a.min(1, keepdims = 1))
     ...: a_masked = ma.masked_array(a, mask = mask)
     ...: out = a_masked.mean(1).data
1 loop, best of 3: 251 ms per loop

# Posted in here
In [184]: %%timeit
     ...: m = (a!=a.min(1,keepdims=1)) & (a!=a.max(1,keepdims=1))
     ...: out = (a*m).sum(1)/m.sum(1).astype(float)
10 loops, best of 3: 165 ms per loop

# Posted in here with additional einsum
In [185]: %%timeit
     ...: m = (a!=a.min(1,keepdims=1)) & (a!=a.max(1,keepdims=1))
     ...: out = np.einsum('ij,ij->i',a,m)/m.sum(1).astype(float)
10 loops, best of 3: 124 ms per loop

答案 4 :(得分:0)

如果问题是要从numpy数组arr中删除最小和/或最大元素,那么我认为这是最简单的方法。

np.delete(arr, np.argmax(arr))

示例

tmp = np.random.random(3)
print(tmp)

tmp = np.delete(tmp, np.argmax(tmp))
print(tmp)

返回

[0.7366768  0.65492774 0.93632866]
[0.7366768  0.65492774]