当您需要调试此类事情时,将其分解为更简单的步骤很有用。您是否弄错了切片,添加了两个不兼容的数组类型,添加了两种类型但试图将结果粘贴到不兼容的类型中(当+ 可以但= 不行时使用+=),或者添加不兼容的数据值?其中任何一个都可以提出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' 不是您在Data types 的用户指南部分看到的友好数据类型之一,它是一个结构定义,如Structured arrays 部分所述。意思是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 的大部分好处来自于使用严格的 C/Fortran 风格的数据类型,numpy 知道如何使用它们——它可以将它们紧密打包,无需额外取消引用(并且无需引用计数)即可访问它们,在在没有 Python 的任何帮助的情况下,以各种方式从乘法到复制到打印等。但它不能进行字符串操作。如果您尝试对字符串操作进行矢量化,则说明您使用了错误的库来执行此操作。如果您只是因为有人说它很快而使用numpy,那么,在很多情况下都是这样,但在这个情况下则不然。如果您使用 numpy 是因为其他代码正在向您提供 numpy 数据,但您不想以 numpy 的方式处理它,那么没有什么能阻止您将其转换为纯 Python 数据。