用字符切片一个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】:您必须将int
与int
进行比较
A[A[:,4].astype(int)<30]
或str
到str
A[A[:,4]<'30']
但是,请注意后者可以在您的具体示例中工作,但通常不会工作,因为您正在比较 str
排序(例如,'110' < '30'
返回 True
,但是110 < 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]<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数组的主要内容,如果未能解决你的问题,请参考以下文章