当您需要调试此类事情时,将其分解为更简单的步骤很有用。您是否弄错了切片,添加了两种不兼容的数组类型,添加了两种类型但试图将结果粘贴到不兼容的类型中(使用+=
when+
是 OK 但=
不是),或者添加不兼容的数据值?其中任何一个都可以提高TypeError
,那么我们怎么知道你在做什么呢?
好吧,一次做,看看:
切片:
>>> src[:, 1]
array(['b', 'd', 'f'], dtype='|S1')
>>> src[:, 1] = ['x', 'y', 'z']
>>> src
>>> array([['a', 'x'], ['c', 'y'], ['e', 'z']], dtype='|S1')
没关系。添加呢?
>>> src + src2
TypeError: unsupported operand type(s) for +: 'numpy.ndarray' and 'numpy.ndarray'
因此,我们已经发现了与您的更复杂情况相同的错误,没有切片,也没有+=
,这使得调试更加容易。让我们更简单:
>>> s1, s2 = np.array('a'), np.array('b')
>>> s1 + s2
TypeError: unsupported operand type(s) for +: 'numpy.ndarray' and 'numpy.ndarray'
所以即使添加两个 0D 数组也会失败!没有比这更简单的了。
也许是数据类型。如果我们使用整数会发生什么?
>>> n1, n2 = np.array(1), np.array(2)
>>> n1 + n2
3
你可以一直回到你原来的例子,使用整数而不是字符串,它仍然可以正常工作:
>>> m1 = np.array([[1,2], [3,4], [5,6]])
>>> m2 = np.array([[7], [8], [9]])
>>> m1[:, 1] += m2[:, 0]
>>> array([[ 1, 9],
[ 3, 12],
[ 5, 15]])
这应该很明显问题出在数据类型上。那么,数据类型是什么?只需打印出数组,看看numpy
它是什么:
>>> src = numpy.array([["a", "b"], ["c", "d"], ["e", "f"]])
>>> src
array([['a', 'b'], ['c', 'd'], ['e', 'f']], dtype='|S1')
这'|S1'
不是您在数据类型的用户指南部分中看到的友好数据类型之一,它是一个结构定义,如结构化数组部分中所述。这意味着一个 1 个字符的固定长度字符串。
这使问题变得显而易见:您不能添加两个 1 字符的固定长度字符串,因为结果不是 1 字符的固定长度字符串。
如果您真的想按原样工作,简单的解决方案是将它们保留为 Python 字符串:
>>> src = numpy.array([["a", "b"], ["c", "d"], ["e", "f"]], dtype=object)
>>> src2 = numpy.array([["x"], ["y"], ["z"]], dtype=object)
>>> src[:, 1] += src2[:, 0]
没有了TypeError
。
或者,如果您明确给出src
dtype |S2
,numpy
将允许这样做,并且第二个字符将为空白。它不会让你在其中添加另一个|S1
,但你可以在 Python 中循环,或者找到一种复杂的方法来numpy
为你做这件事。无论哪种方式,您当然不会获得任何通常的时间性能优势numpy
,但您仍然可以获得使用固定尺寸固定单元的空间性能优势。
但你可能想退后一步,问问你想离开numpy
这里做什么。你在这里的实际更高层次的目标是什么?大部分好处numpy
来自使用numpy
知道如何使用的严格的 C/Fortran 风格的数据类型——它可以将它们紧密打包,无需额外的解引用(并且无需引用计数)即可访问它们,以多种方式进行操作,从乘法到在没有 Python 等帮助的情况下复制到打印,但它不能进行字符串操作。如果您尝试对字符串操作进行矢量化,则说明您使用了错误的库来执行此操作。如果您只是numpy
因为有人说它很快而使用它,那么在很多情况下都是如此,但在这一次却不是。如果您正在使用numpy
,因为其他一些代码正在向您传递numpy
数据,但您没有numpy
方式,没有什么能阻止您将其转换为纯 Python 数据。