有更好的方法将字符串操作应用于ndarrays而不是遍历它们吗?我想使用“向量化”操作,但是我只能想到使用map(显示的示例)或列表推导。
ndarray
map
Arr = numpy.rec.fromrecords(zip(range(5),'as far as i know'.split()), names='name, strings') print ''.join(map(lambda x: x[0].upper()+'.',Arr['strings'])) => A.F.A.I.K.
例如,在R语言中,字符串操作也被向量化:
> (string <- unlist(strsplit("as far as i know"," "))) [1] "as" "far" "as" "i" "know" > paste(sprintf("%s.",toupper(substr(string,1,1))),collapse="") [1] "A.F.A.I.K."
更新: 请参见Larsman对这个问题的回答:Numpy最近添加了一个numpy.char用于基本字符串操作的模块。
numpy.char
是的,最近的NumPy在numpy.char模块中已经向量化了字符串操作。例如,当您要在字符串数组中查找所有以B开头的字符串时,
>>> y = np.asarray("B-PER O O B-LOC I-LOC O B-ORG".split()) >>> y array(['B-PER', 'O', 'O', 'B-LOC', 'I-LOC', 'O', 'B-ORG'], dtype='|S5') >>> np.char.startswith(y, 'B') array([ True, False, False, True, False, False, True], dtype=bool)
简短答案: Numpy不提供向量化字符串操作。惯用的方法是执行类似的操作(Arr您的numpy数组在哪里):
Arr
print '.'.join(item.upper() for item in Arr['strings'])
长答案,这就是为什么numpy不提供向量化的字符串操作的原因:(以及两者之间的很多杂乱无章)
就数据结构而言,一种大小并不适合所有情况。
对于非特定领域编程语言的人来说,您的问题似乎很奇怪,但是对于特定领域编程语言的人来说,这很有意义。
Python为您提供了多种数据结构选择。有些数据结构在某些任务上比其他任务更好。
首先,numpy数组不是python中默认的“容纳所有”容器。Python的内置容器 非常 擅长于其设计用途。通常,列表或字典就是您想要的。
Numpyndarray表示同质数据。
简而言之,numpy没有向量化的字符串操作。
ndarrays是一个专用容器,专注于以尽可能少的内存存储N维 同质 的项目组。重点实际上是最大程度地减少内存使用(我有偏见,因为这主要是我所需要的,但这是思考它的一种有用方法。)。向量化的数学运算只是将事物存储在连续的内存块中的一个很好的副作用。
字符串通常具有不同的长度。
例如['Dog', 'Cat', 'Horse']。Numpy采用类似于数据库的方法,要求您定义字符串的长度,但是简单的事实是,字符串不应该是固定的长度,这有很多含义。
['Dog', 'Cat', 'Horse']
最有用的字符串操作返回可变长度的字符串。(例如'.'.join(...)在您的示例中)
'.'.join(...)
如果您不愿意的话(例如鞋帮等),您可以模仿其他操作。(例如,鞋帮大概是(x.view(np.uint8) - 32).view('S1')。我不建议您这样做,但是您可以…)
(x.view(np.uint8) - 32).view('S1')
作为一个基本示例:'A' + 'B'yields 'AB'。 'AB'与'A'或的长度不同'B'。Numpy处理其他可以做到这一点的事情(例如np.uint8(4) + np.float(3.4)),但是字符串的长度比数字的长度灵活得多。(数字的“上播”和“下播”规则非常简单。)
'A' + 'B'
'AB'
'A'
'B'
np.uint8(4) + np.float(3.4)
numpy不这样做的另一个原因是,重点放在 数值 运算上。 'A'**2在python中没有特定的定义(您当然可以创建一个字符串类,但是应该是什么?)。字符串数组是numpy中的二等公民。它们存在,但是大多数操作并未为其定义。
'A'**2
Python已经 非常 擅长处理字符串处理
numpy不尝试提供字符串操作的另一个(也是最主要的)原因是python已经 非常 擅长于此。
列表是出色的灵活容器。Python有很多非常好的,非常快的字符串操作。列表推导和生成器表达式相当快,并且它们不必在乎尝试猜测返回项的类型或大小应该是什么,因此不会增加任何开销。(他们只是存储一个指向它的指针。)
另外,在python中遍历numpy数组比在python中遍历列表或元组要慢,但是对于字符串操作,最好只使用普通的list /generator表达式。(例如,print '.'.join(item.upper() for item in Arr['strings'])在您的示例中)更好的是,不要首先使用numpy数组存储字符串。如果您的结构化数组中只有一列包含字符串,这是很有意义的,但是仅此而已。Python为您提供了 非常 丰富和灵活的数据结构。Numpy数组不是全部,也不是全部,它们是特殊情况,而不是一般情况。
另外,请记住,您最想使用numpy数组进行的操作
学习Python,而不仅仅是Numpy
我不想在这里变得厚脸皮,但是使用numpy数组与Matlab或R或IDL等中的很多东西非常相似。
这是一个熟悉的范例,任何人的第一个直觉是尝试将相同的范例应用于语言的其余部分。
Python不仅仅是numpy。它是一种多范式语言,因此很容易遵循您已经习惯的范式。尝试学习“用python思维”以及“用numpy思维”。Numpy为python提供了一个特定的范例,但还有很多,并且某些范例比其他范例更适合某些任务。
部分原因是逐渐熟悉了不同数据容器(列表,字典,元组等)的优缺点,以及不同的编程范例(例如,面向对象,功能,过程等)。
总而言之,python具有几种不同类型的专用数据结构。这使其与R或Matlab等领域特定的语言有所不同,R或Matlab具有几种类型的数据结构,但着重于使用一种特定的结构进行所有操作。(我对R的经验是有限的,所以我可能在那儿错了,但是无论如何,这就是我的印象。无论如何,Matlab的确如此。)
无论如何,我并不想在这里抱怨,但是我花了相当长的时间才停止在Matlab中编写Fortran,并且花了我更长的时间才停止在python中编写Matlab。这个漫不经心的答案在具体示例上是很合理的,但希望它至少有意义一点,并有所帮助。