使用字符串含义列表,从整数ndarray的'标志'创建字符串ndarray

3
我将尝试从一个整数“标记”ndarray转换:
array([[1, 3, 2],
       [2, 0, 3],
       [3, 2, 0],
       [2, 0, 1]])

将一个ndarray转换成字符串数组:

array([['Banana', 'Celery', 'Carrot'],
       ['Carrot', 'Apple', 'Celery'],
       ['Celery', 'Carrot', 'Apple'],
       ['Carrot', 'Apple', 'Banana']],
      dtype='|S6')

使用字符串列表作为“标志”到“含义”的映射:

meanings = ['Apple', 'Banana', 'Carrot', 'Celery']

我想到了以下内容:
>>> import numpy as np
>>> meanings = ['Apple', 'Banana', 'Carrot', 'Celery']
>>> flags = np.array([[1,3,2],[2,0,3],[3,2,0],[2,0,1]])
>>> flags
array([[1, 3, 2],
       [2, 0, 3],
       [3, 2, 0],
       [2, 0, 1]])
>>> mapped = np.array([meanings[f] for f in flags.flatten()]).reshape(flags.shape)
>>> mapped
array([['Banana', 'Celery', 'Carrot'],
       ['Carrot', 'Apple', 'Celery'],
       ['Celery', 'Carrot', 'Apple'],
       ['Carrot', 'Apple', 'Banana']],
      dtype='|S6')

这种方法可以运行,但是处理大型的ndarrays时,我担心相关行的效率(列表推导、flattenreshape):

np.array([meanings[f] for f in flags.flatten()]).reshape(flags.shape)

有没有更好/更有效的方法执行这样的映射?
2个回答

3

Fancy indexing是使用numpy的方式:

mapped = meanings[flags]

或者通常更快的等效方法:
mapped = np.take(meanings, flags)

谢谢@Jamie。不过需要注意的是,只有使用np.take的第二种解决方案适用于ndims > 1的情况。对于我的例子,第一种解决方案会导致以下错误:TypeError: only integer arrays with one element can be converted to an index - blazetopher
这是因为 meanings 是一个列表。如果你将它转换成一个 ndarray(即 meanings = np.array(meanings)),那么两种方法都可以同样地工作。 - Jaime

2

我认为使用 np.vectorize 是正确的方法,而且非常清晰易懂。我还没有测试下面的代码,但应该可以工作。

vfunc = np.vectorize(lambda x : meanings[x])

mapped = vfunc(flags)

谢谢,这个方法非常有效 - 不过你有个拼写错误:mapped = vfunc(flags) - blazetopher
np.vectorize是Python中的一个伪装循环,而且你每个数组项都要进行一次Python调用。它可以让代码看起来更简洁,但会给人一种错误的印象,即你将获得numpy的性能,实际上并不是这样的。 - Jaime
长期以来,我一直认为 np.vectorize 是用 Cython 编写和编译的,这使它在性能上具有优势,但是 Jamie 是正确的,它是 纯 Python - lukecampbell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接