用字符切片一个numpy数组

Posted

技术标签:

【中文标题】用字符切片一个numpy数组【英文标题】:slicing a numpy array with characters 【发布时间】:2018-10-09 22:23:15 【问题描述】:

我有一个文本文件:

0.01 1 0.1 1 10 100 a
0.02 3 0.2 2 20 200 b
0.03 2 0.3 3 30 300 c
0.04 1 0.4 4 40 400 d

我把它读成一个列表A,然后转换成一个numpy数组,即:

>>> A
array([['0.01', '1', '0.1', '1', '10', '100', 'a'],
       ['0.02', '3', '0.2', '2', '20', '200', 'b'],
       ['0.03', '2', '0.3', '3', '30', '300', 'c'],
       ['0.04', '1', '0.4', '4', '40', '400', 'd']], 
      dtype='|S4')

我只想提取一个子数组 B,由 A 组成,只要它的第 4 个条目低于 30,它应该看起来像:

B = array([['0.01', '1', '0.1', '1', '10', '100', 'a'],
           ['0.02', '3', '0.2', '2', '20', '200', 'b']])

在处理数组时,我通常只使用B = A[A[:,4]<30],但在这种情况下(可能是由于我从未使用过的字符/字符串的存在)它不起作用,给我这个:

>>> A[A[:,4]<30]
array(['0.01', '1', '0.1', '1', '10', '100', 'a'], 
      dtype='|S4')

我不知道原因。我不是在处理我的代码,我认为我不能将所有这些切换到结构或字典:对使用 numpy 数组执行此操作有什么建议吗?非常感谢您!

【问题讨论】:

【参考方案1】:

您必须将intint 进行比较

A[A[:,4].astype(int)<30]

strstr

A[A[:,4]<'30'] 

但是,请注意后者可以在您的具体示例中工作,但通常不会工作,因为您正在比较 str 排序(例如,'110' &lt; '30' 返回 True,但是110 &lt; 30 返回False)


numpy 将从您的数据中推断出元素的类型。在这种情况下,它将type = '|S4' 归因于您的元素,这意味着它们的长度为4。这可能是底层C 代码(增强numpy 的性能)要求元素具有固定类型的结果.

为了说明这种差异,请检查以下代码:

>>> np.array([['0.01', '1', '0.1', '1', '10', '100', 'a']])
array(['0.01', '1', '0.1', '1', '10', '100', 'a'], dtype='|S4')

长度为 4 的字符串的推断类型,即元素的最大长度(在 elem 0.01 中)。现在,如果你明确定义它来保存通用类型对象,它会做你想做的事

>>> np.array([[0.01, 1, 0.1, 1, 10, 100, 'a']], dtype=object)
array([0.01, 1, 0.1, 1, 10, 100, 'a'], dtype=object)

您的代码A[A[:,4]&lt;30] 可以正常工作。

如需了解更多信息,this 是一份非常完整的指南

【讨论】:

但是当我处理文件时,我将它们读取为整数和浮点数,为什么当我传递给numpy数组时它们会变成字符串? 它转换为str,因为您的数组具有不同类型的元素。 NumPy 尝试推断您的元素的类型 天啊,我没有注意到我的数组是由字符串组成的!当我读取文件时,我创建了一个列表列表,并将每个条目读取为整数、浮点数或字符串。我不明白为什么 numpy 将它们全部更改为字符串...【参考方案2】:
In [86]: txt='''0.01 1 0.1 1 10 100 a
    ...: 0.02 3 0.2 2 20 200 b
    ...: 0.03 2 0.3 3 30 300 c
    ...: 0.04 1 0.4 4 40 400 d'''
In [87]: A = np.genfromtxt(txt.splitlines(), dtype=str)
In [88]: A
Out[88]: 
array([['0.01', '1', '0.1', '1', '10', '100', 'a'],
       ['0.02', '3', '0.2', '2', '20', '200', 'b'],
       ['0.03', '2', '0.3', '3', '30', '300', 'c'],
       ['0.04', '1', '0.4', '4', '40', '400', 'd']], dtype='<U4')
In [89]: A[:,4]
Out[89]: array(['10', '20', '30', '40'], dtype='<U4')

genfromtxt,默认情况下会尝试制作浮点数。但在这种情况下,字符列将是nan。相反,我指定了str dtype。

因此,数字测试需要将列转换为数字:

In [90]: A[:,4].astype(int)
Out[90]: array([10, 20, 30, 40])
In [91]: A[:,4].astype(int)<30
Out[91]: array([ True,  True, False, False])

在这种情况下,字符串比较也有效:

In [99]: A[:,4]<'30'
Out[99]: array([ True,  True, False, False])

或者如果我们使用 dtype=None,它会按列推断 dtype 并生成结构化数组:

In [93]: A1 = np.genfromtxt(txt.splitlines(), dtype=None,encoding=None)
In [94]: A1
Out[94]: 
array([(0.01, 1, 0.1, 1, 10, 100, 'a'), (0.02, 3, 0.2, 2, 20, 200, 'b'),
       (0.03, 2, 0.3, 3, 30, 300, 'c'), (0.04, 1, 0.4, 4, 40, 400, 'd')],
      dtype=[('f0', '<f8'), ('f1', '<i8'), ('f2', '<f8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8'), ('f6', '<U1')])

现在我们可以按名称选择一个字段,并对其进行测试:

In [95]: A1['f4']
Out[95]: array([10, 20, 30, 40])

无论哪种方式,我们都可以根据真/假掩码或相应的行索引来选择行:

In [96]: A[[0,1],:]
Out[96]: 
array([['0.01', '1', '0.1', '1', '10', '100', 'a'],
       ['0.02', '3', '0.2', '2', '20', '200', 'b']], dtype='<U4')

In [98]: A1[[0,1]]     # A1 is 1d
Out[98]: 
array([(0.01, 1, 0.1, 1, 10, 100, 'a'), (0.02, 3, 0.2, 2, 20, 200, 'b')],
      dtype=[('f0', '<f8'), ('f1', '<i8'), ('f2', '<f8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8'), ('f6', '<U1')])

【讨论】:

以上是关于用字符切片一个numpy数组的主要内容,如果未能解决你的问题,请参考以下文章

NumPy 数组切片索引

numpy数组的索引和切片

对比 Python 原生切片,讲述 Numpy 数组切片!

numpy 切片

一次从 numpy 数组中选择多个切片

Numpy数组获取不是NaN的数组的子集/切片