初始化一个包含字符串数据的numpy数组时出现奇怪的行为

57

当数组中包含字符串数据时,我在使用numpy时遇到了一些看似微不足道的麻烦。我有以下代码:

my_array = numpy.empty([1, 2], dtype = str)
my_array[0, 0] = "Cat"
my_array[0, 1] = "Apple"
现在,当我使用print my_array[0, :]打印它时,我得到的回应是['C', 'A'],这显然不是预期的Cat和Apple的输出。为什么会这样,我该如何获得正确的输出呢?
谢谢!
6个回答

75

Numpy需要字符串数组具有固定的最大长度。当您使用dtype=str创建一个空数组时,默认情况下它将此最大长度设置为1。如果您执行my_array.dtype,您会看到它显示为"|S1",表示“单字符字符串”。对该数组进行后续赋值时将截断以适应此结构。

您可以通过指定数据类型和最大长度来传递参数,例如:

my_array = numpy.empty([1, 2], dtype="S10")

"S10"将创建一个长度为10的字符串数组。您必须决定足够大以容纳要保存的所有数据。


一旦我在列表中更新一个元素(即 my_array[0] = 'hello'),那么第一个元素是否仍具有分配的“10个字符的内存空间”?还是它现在真正是一个“S5”对象?我认为不是,因为numpy数组的dtype必须在整个数组中保持一致。 - pretzlstyle
@jphollowed:对的,整个数组的大小是固定的,所以如果你将其初始化为S10,即使实际存储的字符串较小,它仍将使用每个条目的10个字节。 - BrenBarn
1
为什么我应该使用这个而不是 dtype=object?它会更快吗? - Boern
@Boern:在大多数情况下,字符串数据类型比对象数据类型更快。但是如果您不太关心速度,使用对象数据类型也是可以的。 - BrenBarn
2
最好还是抽象化并且有泄漏,胜过从未抽象化。 - profPlum
显示剩余4条评论

21

当我尝试在dtype="S10"中使用非ASCII字符时,出现了“编解码器错误”。

你也可以得到一个由二进制字符串组成的数组,这让我感到困惑。

我认为最好使用:

my_array = numpy.empty([1, 2], dtype="<U10")

这里的'U10'表示“长度为10的Unicode字符串;小端格式”。


2
如果解释了 dtype = "<U10" 的含义,这将是一个更好的答案。 - eric

12

numpy字符串数组的长度是固定的(默认长度为1)。如果您不确定在事先需要的字符串长度,可以使用dtype=object来获取数据元素的任意长度字符串:

my_array = numpy.empty([1, 2], dtype=object)

我知道这种方法可能存在效率上的缺陷,但我没有一个好的参考来支持这一点。


与“S10”相比,是否存在任何注意事项(如速度较慢)? - Boern

1

如果有新手在这里,我猜现在还有另一种方法可以完成这项工作,只需要做一点点工作:

my_array = np.full([1, 2], "", dtype=np.object)

使用 np.full 替代 np.empty,并使用空字符串(类型为对象)创建数组。

0

另一种选择是按以下方式初始化:

my_array = np.array([["CAT","APPLE"],['','']], dtype=str)

换句话说,首先您使用所需内容编写常规数组,然后将其转换为numpy数组。但是,这将使您的最大字符串长度固定为初始化时最长字符串的长度。因此,如果您要添加
my_array[1,0] = 'PINEAPPLE'

那么存储的字符串将是'PINEA'。


0
如果您正在进行for循环,则最好使用列表推导式,这将允许您分配正确的内存。
data = ['CAT', 'APPLE', 'CARROT']
my_array = [name for name in data]

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