从基于列的数组返回多数加权投票

her*_*uzz 5 python numpy numpy-ndarray

我有一个矩阵x,其3 x 3维度和向量w3,

x = np.array([[1, 2, 1],
              [3, 2 ,1],
              [1, 2, 2]])

w = np.array([0.3, 0.4, 0.3])
Run Code Online (Sandbox Code Playgroud)

我需要生成另一个向量y,该向量对 x. 的每一列x由 中的相应值加权w。像这样的东西:

for y[0],它应该寻找X[0] => [1, 2, 1]

  • 值为 1 = 第一和第三 [0,2] 的列
  • 值为 2 = 秒 [1] 的列
  • 值为 3 = 无的列

w按其在 X 中的值分组的列的权重 (in )求和:

  • 值为 1 的列的权重总和: 0.3 + 0.3 = 0.6
  • 值为 2 的列的权重总和: 0.4
  • 值为 3 的列的权重总和: 0

由于值为 1 的列的权重总和最高,因此y[0] = 1. 等等。

Jav*_*lez 4

如果您了解广播,则可以使用 numpy 来完成。缺点是,由于代码是矢量化的,因此您执行的计算量会超出您的需要。如果向量的大小w非常大,这会很重要。

也许有人想出了一种更简单的方法来编写它,但这就是我不会考虑太多的方式。

先回答一下:

i = np.arange(3) + 1
m = (x.reshape((1,4,3)) == i.reshape((3,1,1)))
np.argmax(np.sum(m, axis=2).T*w, axis=1) + 1
Run Code Online (Sandbox Code Playgroud)

现在逐步解释...请注意,通常最好从零开始计数,但我遵循了您的约定。

  1. 我添加了一行,因此数组不对称(更容易检查形状)

     In [1]: x = np.array([[1, 2, 1],
        ...:               [3, 2 ,1],
        ...:               [1, 2, 2],
        ...:               [3, 1, 3]])
        ...:
        ...: w = np.array([0.3, 0.4, 0.3])
    
    Run Code Online (Sandbox Code Playgroud)
  2. 第一步是获得索引数组i。您的会议从一开始。

     In [2]: i = np.arange(3) + 1
    
    Run Code Online (Sandbox Code Playgroud)
  3. 棘手的步骤:创建一个形状为 (3,4,3) 的数组,其中数组的第 i 个条目是一个 (4,3) 数组,所有条目都是 0 或 1。当且仅当 x = = i. 这是通过添加维度来完成的xi因此它们可以被广播。x该操作基本上比较和的所有组合i,因为x匹配大小的所有维度=1 维度i,反之亦然:

     In [3]: m = (x.reshape((1,4,3)) == i.reshape((3,1,1)))*1
    
     In [4]: m
     Out[4]:
     array([[[1, 0, 1],
             [0, 0, 1],
             [1, 0, 0],
             [0, 1, 0]],
    
            [[0, 1, 0],
             [0, 1, 0],
             [0, 1, 1],
             [0, 0, 0]],
    
            [[0, 0, 0],
             [1, 0, 0],
             [0, 0, 0],
             [1, 0, 1]]])
    
    Run Code Online (Sandbox Code Playgroud)
  4. 现在,您沿行求和(即 axis=2),以获得每个选择出现在每行中的次数x(请注意,当您将其与 进行比较时,结果会被转置x):

     In [5]: np.sum(m, axis=2)
     Out[5]:
     array([[2, 1, 1, 1],
            [1, 1, 2, 0],
            [0, 1, 0, 2]])
    
    Run Code Online (Sandbox Code Playgroud)
  5. 我希望你已经知道事情的发展方向了。可以直接读:在第一行中x1出现了两次,2出现了一次。在 的第二行中x, 全部出现一次,在 的第三行中x1出现一次,2出现两次,以此类推。

  6. 将其乘以权重:

     In [7]: np.sum(m, axis=2).T*w
     Out[7]: 
     array([[0.6, 0.4, 0. ],
            [0.3, 0.4, 0.3],
            [0.3, 0.8, 0. ],
            [0.3, 0. , 0.6]])
    
    Run Code Online (Sandbox Code Playgroud)
  7. 获取沿行的最大值(添加一个以符合您的约定):

     In [8]: np.argmax(np.sum(m, axis=2).T*w, axis=1) + 1
     Out[8]: array([1, 2, 2, 3])
    
    Run Code Online (Sandbox Code Playgroud)

特殊情况:领带

评论中提到了以下案例:

x = np.array([[2, 2, 4, 1]])
w = np.array([0.1, 0.2, 0.3, 0.4])
Run Code Online (Sandbox Code Playgroud)

权重之和为:

[0.1, 0.4, 0., 0.4]
Run Code Online (Sandbox Code Playgroud)

所以在这种情况下没有赢家。从这个问题来看,并不清楚在这种情况下人们会做什么。可以全取,也可以全取……可以在最后查找这些案例:

final_w = np.sum(m, axis=2).T*w
result = np.argmax(np.sum(m*w, axis=2), axis=0) + 1
special_cases = np.argwhere(np.sum(final_w == np.max(final_w), axis=1) > 1)
Run Code Online (Sandbox Code Playgroud)

注意:为了可读性,我使用了 reshape 方法,但我经常使用np.expand_dims或 np.newaxis。像这样的东西:

i = np.arange(3) + 1
m = (x[np.newaxis] == i[:, np.newaxis, np.newaxis])
np.argmax(np.sum(m, axis=2).T*w, axis=1) + 1
Run Code Online (Sandbox Code Playgroud)

另一种选择:您还可以使用某种编译代码。例如,numba 在这种情况下非常容易使用。