【问题标题】:Apply udf element-wise in any-dimensional arrays在任意维数组中按元素应用 udf
【发布时间】:2021-01-03 13:39:54
【问题描述】:

所以我有以下函数,它给定一个数字数组来删除异常值:

def reject_outliers(data, m = 1):
    d = np.abs(data - np.median(data))
    mdev = np.median(d)
    s = d/mdev if mdev else 0
    return np.array(data)[s<m]

vec_reject_outliers = np.vectorize(reject_outliers)

我想在多个多维数组中逐元素应用此函数。在下面的示例中,我尝试在列表中的 3 个嵌套数组之间找到每个元素的平均值:

a = np.array([np.array([4000, np.array([12,10])]), np.array([50, np.array([13, 11])]), np.array([51,np.array([30,20])])])

result = [vec_reject_outliers(l, m = 1).mean(axis = 0) for l in zip(*a)]

result 应该是[51, array([13, 11])],因为某些数字将被视为异常值,因此会从计算中删除。然而我得到的结果是[1367.0, array([18.33333333, 13.66666667])],这是在不省略任何元素的情况下计算的平均值。

有没有办法在这种情况下明智地执行reject_outliers 元素,或者我可以通过任何其他方式在任意维数组之间实现预期的result

【问题讨论】:

  • 你的多维数组在哪里? a的形状是什么?看起来像 1d 与 object dtype。 vectorize 只是迭代外部数组。为什么不直接使用列表推导式?
  • 我希望这个函数能够在预先知道它们的维度的任何多维数组之间工作。 a里面是3个多维数组。
  • 您的a 是二维的。有些元素是标量,有些是 1d。

标签: python arrays numpy multidimensional-array user-defined-functions


【解决方案1】:

print 添加到您的函数中,以查看发送给它的确切数据:

In [65]: def reject_outliers(data, m = 1):
    ...:     print('data',data)
    ...:     d = np.abs(data - np.median(data))
    ...:     mdev = np.median(d)
    ...:     s = d/mdev if mdev else 0
    ...:     return np.array(data)[s<m]
    ...: 
In [66]: vec_reject_outliers = np.vectorize(reject_outliers)
In [67]: result = [vec_reject_outliers(l, m = 1).mean(axis = 0) for l in zip(*a)]
data 4000              # trial run to determine otypes
data 4000
data 50
data 51
data 12           # trial run for 2nd tuple
data 12
data 10
data 13
data 11
data 30
data 20

所以每次调用reject 都是一个元素。这就是你想要的对吧?

在多个多维数组中逐元素应用此函数

但是让我们看看你的数组

In [68]: a
Out[68]: 
array([[4000, array([12, 10])],
       [50, array([13, 11])],
       [51, array([30, 20])]], dtype=object)
In [69]: a.shape
Out[69]: (3, 2)
In [70]: a[:,0]
Out[70]: array([4000, 50, 51], dtype=object)
In [71]: a[:,1]
Out[71]: array([array([12, 10]), array([13, 11]), array([30, 20])], dtype=object)

l 被传递给vec... - 两个元组

In [77]: list(zip(*a))
Out[77]: [(4000, 50, 51), (array([12, 10]), array([13, 11]), array([30, 20]))]

所以vec... 被调用了两次,这两个数组各调用一次:

In [82]: np.array(Out[77][0])
Out[82]: array([4000,   50,   51])
In [83]: np.array(Out[77][1])
Out[83]: 
array([[12, 10],
       [13, 11],
       [30, 20]])

然后它用Out[82] 的元素调用reject...,然后用Out[83] 的元素调用。

我还没有试图弄清楚 reject... 究竟做了什么,或者应该传递什么,但显然 vectorize 没有按你的意愿工作。我建议放弃它并进行显式迭代。这样你就有更多的控制权。


在理解中使用reject

In [84]: result = [reject_outliers(l, m = 1).mean(axis = 0) for l in zip(*a)]
data (4000, 50, 51) 1
data (array([12, 10]), array([13, 11]), array([30, 20])) 1
In [85]: result
Out[85]: [51.0, 12.0]

reject单独应用到a的第二列:

In [87]: result = [reject_outliers(l, m = 1).mean(axis = 0) for l in zip(*a[:,1])]
data (12, 13, 30) 1
data (10, 11, 20) 1
In [88]: result
Out[88]: [13.0, 11.0]

并直接使用a 的第一列:

In [91]: reject_outliers(a[:,0], m = 1).mean(axis = 0)
data [4000 50 51] 1
Out[91]: 51.0

【讨论】:

  • 感谢您的回答。我实际上希望result 是以下 [51, array([13, 11])]。这将计算如下。 4000, 50, 51 将作为输入给reject_outliers,它将输出 51,然后 12,13,30 作为输入给reject_outliers,它将输出 13,最后 10, 11,20 作为输入到reject_outliers,它将输出 11,因此最终结果将是 [51, array([13, 11])],它与 a 中的 3 个嵌套数组具有相同的形状。
  • 我可以通过直接调用reject... 来获取这些号码,但要分别处理a[:,0]a[:,1]。只有第二个适用于zip
猜你喜欢
  • 2020-06-06
  • 2021-12-09
  • 2016-11-03
  • 2010-10-17
  • 2017-03-22
  • 1970-01-01
  • 2019-01-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多