【问题标题】:Replacing numbers in numpy array with the ones in the list用列表中的数字替换 numpy 数组中的数字
【发布时间】:2019-07-26 16:35:58
【问题描述】:

我有一个 2D numpy 数组,我希望用索引列表的数字替换它的内容。

这里有一个代码sn-p来描述更清楚:

import numpy as np
x = np.array([
              [2, 'something'],
              [2, 'more'],
              [6, 'and more'],
              [11, 'and so on'],
              [11, 'etc..']
             ])

y = [1, 2, 3]

我尝试通过以下代码执行此操作,但出现错误,无法弄清楚为什么会发生。

k = x[:, 0]
z = [2, 6, 11]
j = 0
for i in range(z[0], z[-1] + 1):
    k = np.where(i in k, y[j])
    j+=1

运行上述代码时出错:

Traceback (most recent call last):

  File "<ipython-input-10-c48814c42718>", line 4, in <module>
    k = np.where(i in k, y[j])

ValueError: either both or neither of x and y should be given

我想要的输出数组:

# The output array which I intend to get
output = [
          [1, 'something'],
          [1, 'more'],
          [2, 'and more'],
          [3, 'and so on'],
          [3, 'etc..']
         ]

【问题讨论】:

  • 您的示例根本不清楚输出数组是如何从导入数组派生的。请用文字解释这个想法,因为你的例子不清楚。你想用列表中最小的数字替换数组第一列中的最小数字,用第二小的数字替换第二小的数字,等等?如果是这样,是否保证数组和列表中的第一列按非降序排序?
  • 输出数组是我打算从x得到的
  • 显示完整的error。还要注意数组的 dtype。我猜它们是字符串 dtype。
  • 编辑了问题
  • 如果稍后出现另一个2,它应该与第一次出现2 共享相同的值,还是不同的值?

标签: python python-3.x numpy


【解决方案1】:

如果我理解正确,这是您可以做到的一种方式:

import numpy as np

x = np.array([
              [2, 'something'],
              [2, 'more'],
              [6, 'and more'],
              [11, 'and so on'],
              [11, 'etc..']
             ])
y = np.array([1, 2, 3])
# Find places where value changes, do cumsum and add a 0 at the beginning, then index y
x[:, 0] = y[np.r_[0, np.cumsum(np.diff(x[:, 0].astype(np.int32)) != 0)]]
# [['1' 'something']
#  ['1' 'more']
#  ['2' 'and more']
#  ['3' 'and so on']
#  ['3' 'etc..']]

注意这里的结果是字符串,因为这是输入数组的类型(NumPy 将强制转换为字符串,除非指定了dtype=object)。无论如何,如果你想拥有混合类型的数组,你应该考虑使用structured array

【讨论】:

  • 感谢@jdehesa,一行代码就像一个魅力!此外,如果我没有遗漏什么,从代码中删除 !=0 仍然有效。
【解决方案2】:

numpy.unique + return_inverse=True

您可以从列中的不同元素创建映射,并使用基本的 numpy 索引将这些值映射到您的输入列表。


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

_, inv = np.unique(x[:, 0], return_inverse=True)

x[:, 0] = y[inv]

array([['1', 'something'],
       ['1', 'more'],
       ['2', 'and more'],
       ['3', 'and so on'],
       ['3', 'etc..']], dtype='<U11')

对这个答案的一个警告是,如果另一个2 出现在数组的后面,它将用1 代替它,而不是用新值,但如果这是一个问题,你需要澄清你的问题.

根据您的替换列表的大小,这似乎是所需的行为。

【讨论】:

    【解决方案3】:

    您可以通过获取唯一值、以暴力方式对它们进行排序以及使用 for 循环进行映射来做到这一点。您需要确保您的映射列表 (y) 也按照从小到大的顺序排列。

    ind = list(x[i][0] for i in range(len(x)))
    
    lookup = set()
    ind = [x for x in ind if x not in lookup and lookup.add(x) is None]
    
    for i in range(len(x)):
               c = ind.index(x[i][0])
               x[i][0] = y[c]
    
    print(x)
    

    输出:

    array([['1', 'something'],
           ['1', 'more'],
           ['2', 'and more'],
           ['3', 'and so on'],
           ['3', 'etc..']], dtype='<U11')
    

    【讨论】:

      【解决方案4】:

      如果您想像当前一样继续使用 for 循环并使用 y 列表,您可以执行以下操作:

      import numpy as np
      
      x = np.array([[2, 'something'], [2, 'more'], [6, 'and more'],
                    [11, 'and so on'], [11, 'etc..']])
      y = [1, 2, 3]
      
      y_index = 0
      for i in range(0, x.shape[0] - 1):
        if x[i+1][0] != x[i][0]:
          x[i][0] = y[y_index]
          y_index += 1
        else:
          x[i][0] = y[y_index]
      x[-1][0] = y[y_index] # Set last index
      
      print(x)
      

      输出:

      [['1' 'something']
       ['1' 'more']
       ['2' 'and more']
       ['3' 'and so on']
       ['3' 'etc..']]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-01-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-29
        • 2021-10-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多