根据与列表的部分匹配过滤 numpy 结构化数组
Filter numpy structured array based on partial match to a list
我有关于我发布的一个跟进问题 。在那个问题中,我试图根据多个条件(包括列表中的匹配项)对 numpy 结构化数组中的值求和。 @ali_m 成功回答了这个问题:
criteriaList = ("Zone1", "Zone2")
myArray = np.array([(1, 1, 1, u'Zone3', 9.223),
(2, 1, 0, u'Zone2', 17.589),
(3, 1, 1, u'Zone2', 26.95),
(4, 0, 1, u'Zone1', 19.367),
(5, 1, 1, u'Zone1', 4.395)],
dtype=[('ID', '<i4'), ('Flag1', '<i4'), ('Flag2', '<i4'), ('ZoneName', '<U5'),
('Value', '<f8')])
result = myArray[(myArray["Flag1"] == 1) & (myArray["Flag2"] == 1)
& np.in1d(myArray["ZoneName"], criteriaList)]["Value"].sum()
这将产生所需的结果 31.345。
现在我想弄清楚如果我的数组中有下划线分隔值并且我想在与 critieriaList 部分匹配的情况下将该行包含在我的总和中,如何修改它。在以下 numpy 结构化数组中,第三行包含下划线分隔值。在这种情况下,我想包含该值,因为 "Zone1" 作为 "ZoneName" 值的一部分包含在内:
myArray = np.array([(1, 1, 1, u'Zone3', 9.223),
(2, 1, 0, u'Zone2', 17.589),
(3, 1, 1, u'Zone1_Zone3', 26.95),
(4, 0, 1, u'Zone1', 19.367),
(5, 1, 1, u'Zone1', 4.395)],
dtype=[('ID', '<i4'), ('Flag1', '<i4'), ('Flag2', '<i4'), ('ZoneName', '<U10'),
('Value', '<f8')])
我尝试拆分数组中的值:
str(myArray["ZoneName"]).split('_')
但是如果不打开循环并使用 if 语句,就无法弄清楚如何处理这些内容。任何帮助将不胜感激。谢谢。
这里是一个使用循环和 if 语句来解决这个问题的例子。这不像所写的那样起作用,但根据 hpualij 的评论概述了我的思考过程。 (如果有 "Zone14",这也会导致问题,因为 "Zone1" 在 "Zone14" 中)
values = []
criteriaList = ("Zone1", "Zone2")
for criteria in criteriaList:
zones = myArray["ZoneName"]
for zone in zones:
if criteria in zone:
print ("criteria=" + criteria)
print ("zone=" + zone)
value = myArray[((myArray["Flag1"] == 1) & (myArray["Flag2"] == 1)
& (myArray["ZoneName"] == zone))]["Value"].sum
print(value)
result = sum(values)
('ZoneName', '<U10')
需要 ('ZoneName', '<U11')
才能包括最后的“3”。
让我们专注于一个领域;我们可以用一个新变量来引用它:
In [321]: names=myArray['ZoneName']
In [322]: names
Out[322]:
array(['Zone3', 'Zone2', 'Zone1_Zone3', 'Zone1', 'Zone1'],
dtype='<U11')
np.char
具有将字符串方法应用于数组元素的函数。让我们试试 split
:
In [323]: np.char.split(names,'_')
Out[323]: array([['Zone3'], ['Zone2'], ['Zone1', 'Zone3'], ['Zone1'], ['Zone1']], dtype=object)
我认为这没有帮助。我们仍然需要迭代来搜索子列表。
In [324]: np.char.find(names,'Zone1')
Out[324]: array([-1, -1, 0, 0, 0])
In [325]: np.char.find(names,'Zone3')
Out[325]: array([ 0, -1, 6, -1, -1])
这看起来好多了。我们现在有一个数字数组; '-1' 表示没有字符串的元素。
在功能上这与
相同
In [326]: np.array([astr.find('Zone1') for astr in names])
Out[326]: array([-1, -1, 0, 0, 0])
我不确定 char.find
节省了多少时间。我想我们可以测试一下。 :)
这会让您克服瓶颈吗?
In [328]: %timeit np.array([astr.find('Zone1') for astr in names])
100000 loops, best of 3: 10.2 µs per loop
In [329]: %timeit np.char.find(names,'Zone1')
10000 loops, best of 3: 21.4 µs per loop
np.char.find
其实比较慢!在 (5000,) 数组上,理解方法仍然更快,尽管余量没有那么大。
另一种选择是 view
字段为 2 个或更多字段:
In [352]: nn = names.view([('1st','U5'),('dash','U1'),('2nd','U5')])
In [353]: nn
Out[353]:
array([('Zone3', '', ''), ('Zone2', '', ''), ('Zone1', '_', 'Zone3'),
('Zone1', '', ''), ('Zone1', '', '')],
dtype=[('1st', '<U5'), ('dash', '<U1'), ('2nd', '<U5')])
In [354]: nn['1st']=='Zone1'
Out[354]: array([False, False, True, True, True], dtype=bool)
In [355]: nn['2nd']=='Zone1'
Out[355]: array([False, False, False, False, False], dtype=bool)
In [356]: (nn['1st']=='Zone1')|(nn['2nd']=='Zone3')
Out[356]: array([False, False, True, True, True], dtype=bool)
In [357]: (nn['1st']=='Zone3')|(nn['2nd']=='Zone3')
Out[357]: array([ True, False, True, False, False], dtype=bool)
这利用了 11
个字符的字符串可以被视为 3 个较短的字符串这一事实。
它比字符串操作快得多 - 如果您可以接受确切的字符数
In [358]: %%timeit
.....: nn = M.view([('1st','U5'),('dash','U1'),('2nd','U5')])
.....: (nn['1st']=='Zone1')|(nn['2nd']=='Zone1')
.....:
1000 loops, best of 3: 264 µs per loop
使用更强大的 re.match
- 大约是 find
.
速度的 1/3
In [368]: %timeit [re.match('Zone1',astr) is not None for astr in M]
100 loops, best of 3: 14.7 ms per loop
In [369]: %timeit np.array([astr.find('Zone1') for astr in M])>-1
100 loops, best of 3: 5.31 ms per loop
糟糕,我希望 re.search
稍后在字符串中匹配。
In [372]: [re.search('Zone3',astr) for astr in names]
Out[372]:
[<_sre.SRE_Match object; span=(0, 5), match='Zone3'>,
None,
<_sre.SRE_Match object; span=(6, 11), match='Zone3'>,
None,
None]
In [376]: %timeit [re.search('Zone1',astr) is not None for astr in M]
100 loops, best of 3: 11.1 ms per loop
优于match
,速度仅为find
的1/2。需要细化模式以区分 Zone1_
和 Zone14
,但使用 re
.
很容易
这是我的问题的有效解决方案,但速度很慢(实际数组有 >200,000 条记录,并且有超过 50 "zones")它根据多个字段对 numpy 结构化数组的值求和,其中 "Flag1" 字段 == 1 AND "Flag2" 字段 == 1 并且 "ZoneName" 字段中至少有一个匹配条件列表中的名称列表。如果 "ZoneName" 字段包含条件列表中的至少一个值(例如 "Zone1_Zone3"),它将找到一个匹配项,如果 "ZoneName" 字段包含条件列表中的多个值,它将不会重复计算列表(例如 "Zone1_Zone2"),它不会将部分匹配项匹配到标准列表(例如 "Zone14")。感谢@hpaulj 的帮助!我欢迎任何关于改进方法的进一步评论,特别是在处理速度方面。
import numpy as np
import re
def main():
#sum values from the array if "Flag1"==1, "Flag2"==1, and "ZoneName" includes
#either "Zone1" or "Zone2"
myArray = np.array([(1, 1, 1, u'Zone3', 9.223),
(2, 1, 0, u'Zone2', 17.589),
(3, 1, 1, u'Zone1_Zone2', 26.95),
(4, 0, 1, u'Zone2', 19.367),
(5, 1, 1, u'Zone1_Zone3', 4.395),
(5, 1, 1, u'Zone15', 8.565),
(5, 1, 1, u'Zone2', 7.125),
(5, 1, 0, u'Zone1', 6.395)],
dtype=[('ID', '<i4'), ('Flag1', '<i4'), ('Flag2', '<i4'), ('ZoneName', '<U15'),
('Value', '<f8')])
doneList = [] #empty list to track which zones have been calc'd
values = [] #empty list to store values from loop
criteriaList = ("Zone1", "Zone2")
zones = myArray["ZoneName"]
for criteria in criteriaList:
for zone in zones:
#only calc if the "ZoneName" value from the array includes the criteria
#in the current loop and the record has not already been calc'd
if ((find_word(str(np.char.split(zone,'_')), criteria)) & (zone not in doneList)):
#the key element from previous question
value = myArray[((myArray["Flag1"] == 1) & (myArray["Flag2"] == 1))
& np.in1d(myArray["ZoneName"], zone)]["Value"].sum()
values.append(value)
doneList.append(zone) #Needed to that "Zone1_Zone2" is not double counted
result = sum(values)
print result
def find_word(text, search):
result = re.findall('\b'+search+'\b', text, flags=re.IGNORECASE)
if len(result)>0:
return True
else:
return False
if __name__ == '__main__':
main()
我有关于我发布的一个跟进问题
criteriaList = ("Zone1", "Zone2")
myArray = np.array([(1, 1, 1, u'Zone3', 9.223),
(2, 1, 0, u'Zone2', 17.589),
(3, 1, 1, u'Zone2', 26.95),
(4, 0, 1, u'Zone1', 19.367),
(5, 1, 1, u'Zone1', 4.395)],
dtype=[('ID', '<i4'), ('Flag1', '<i4'), ('Flag2', '<i4'), ('ZoneName', '<U5'),
('Value', '<f8')])
result = myArray[(myArray["Flag1"] == 1) & (myArray["Flag2"] == 1)
& np.in1d(myArray["ZoneName"], criteriaList)]["Value"].sum()
这将产生所需的结果 31.345。
现在我想弄清楚如果我的数组中有下划线分隔值并且我想在与 critieriaList 部分匹配的情况下将该行包含在我的总和中,如何修改它。在以下 numpy 结构化数组中,第三行包含下划线分隔值。在这种情况下,我想包含该值,因为 "Zone1" 作为 "ZoneName" 值的一部分包含在内:
myArray = np.array([(1, 1, 1, u'Zone3', 9.223),
(2, 1, 0, u'Zone2', 17.589),
(3, 1, 1, u'Zone1_Zone3', 26.95),
(4, 0, 1, u'Zone1', 19.367),
(5, 1, 1, u'Zone1', 4.395)],
dtype=[('ID', '<i4'), ('Flag1', '<i4'), ('Flag2', '<i4'), ('ZoneName', '<U10'),
('Value', '<f8')])
我尝试拆分数组中的值:
str(myArray["ZoneName"]).split('_')
但是如果不打开循环并使用 if 语句,就无法弄清楚如何处理这些内容。任何帮助将不胜感激。谢谢。
这里是一个使用循环和 if 语句来解决这个问题的例子。这不像所写的那样起作用,但根据 hpualij 的评论概述了我的思考过程。 (如果有 "Zone14",这也会导致问题,因为 "Zone1" 在 "Zone14" 中)
values = []
criteriaList = ("Zone1", "Zone2")
for criteria in criteriaList:
zones = myArray["ZoneName"]
for zone in zones:
if criteria in zone:
print ("criteria=" + criteria)
print ("zone=" + zone)
value = myArray[((myArray["Flag1"] == 1) & (myArray["Flag2"] == 1)
& (myArray["ZoneName"] == zone))]["Value"].sum
print(value)
result = sum(values)
('ZoneName', '<U10')
需要 ('ZoneName', '<U11')
才能包括最后的“3”。
让我们专注于一个领域;我们可以用一个新变量来引用它:
In [321]: names=myArray['ZoneName']
In [322]: names
Out[322]:
array(['Zone3', 'Zone2', 'Zone1_Zone3', 'Zone1', 'Zone1'],
dtype='<U11')
np.char
具有将字符串方法应用于数组元素的函数。让我们试试 split
:
In [323]: np.char.split(names,'_')
Out[323]: array([['Zone3'], ['Zone2'], ['Zone1', 'Zone3'], ['Zone1'], ['Zone1']], dtype=object)
我认为这没有帮助。我们仍然需要迭代来搜索子列表。
In [324]: np.char.find(names,'Zone1')
Out[324]: array([-1, -1, 0, 0, 0])
In [325]: np.char.find(names,'Zone3')
Out[325]: array([ 0, -1, 6, -1, -1])
这看起来好多了。我们现在有一个数字数组; '-1' 表示没有字符串的元素。
在功能上这与
相同In [326]: np.array([astr.find('Zone1') for astr in names])
Out[326]: array([-1, -1, 0, 0, 0])
我不确定 char.find
节省了多少时间。我想我们可以测试一下。 :)
这会让您克服瓶颈吗?
In [328]: %timeit np.array([astr.find('Zone1') for astr in names])
100000 loops, best of 3: 10.2 µs per loop
In [329]: %timeit np.char.find(names,'Zone1')
10000 loops, best of 3: 21.4 µs per loop
np.char.find
其实比较慢!在 (5000,) 数组上,理解方法仍然更快,尽管余量没有那么大。
另一种选择是 view
字段为 2 个或更多字段:
In [352]: nn = names.view([('1st','U5'),('dash','U1'),('2nd','U5')])
In [353]: nn
Out[353]:
array([('Zone3', '', ''), ('Zone2', '', ''), ('Zone1', '_', 'Zone3'),
('Zone1', '', ''), ('Zone1', '', '')],
dtype=[('1st', '<U5'), ('dash', '<U1'), ('2nd', '<U5')])
In [354]: nn['1st']=='Zone1'
Out[354]: array([False, False, True, True, True], dtype=bool)
In [355]: nn['2nd']=='Zone1'
Out[355]: array([False, False, False, False, False], dtype=bool)
In [356]: (nn['1st']=='Zone1')|(nn['2nd']=='Zone3')
Out[356]: array([False, False, True, True, True], dtype=bool)
In [357]: (nn['1st']=='Zone3')|(nn['2nd']=='Zone3')
Out[357]: array([ True, False, True, False, False], dtype=bool)
这利用了 11
个字符的字符串可以被视为 3 个较短的字符串这一事实。
它比字符串操作快得多 - 如果您可以接受确切的字符数
In [358]: %%timeit
.....: nn = M.view([('1st','U5'),('dash','U1'),('2nd','U5')])
.....: (nn['1st']=='Zone1')|(nn['2nd']=='Zone1')
.....:
1000 loops, best of 3: 264 µs per loop
使用更强大的 re.match
- 大约是 find
.
In [368]: %timeit [re.match('Zone1',astr) is not None for astr in M]
100 loops, best of 3: 14.7 ms per loop
In [369]: %timeit np.array([astr.find('Zone1') for astr in M])>-1
100 loops, best of 3: 5.31 ms per loop
糟糕,我希望 re.search
稍后在字符串中匹配。
In [372]: [re.search('Zone3',astr) for astr in names]
Out[372]:
[<_sre.SRE_Match object; span=(0, 5), match='Zone3'>,
None,
<_sre.SRE_Match object; span=(6, 11), match='Zone3'>,
None,
None]
In [376]: %timeit [re.search('Zone1',astr) is not None for astr in M]
100 loops, best of 3: 11.1 ms per loop
优于match
,速度仅为find
的1/2。需要细化模式以区分 Zone1_
和 Zone14
,但使用 re
.
这是我的问题的有效解决方案,但速度很慢(实际数组有 >200,000 条记录,并且有超过 50 "zones")它根据多个字段对 numpy 结构化数组的值求和,其中 "Flag1" 字段 == 1 AND "Flag2" 字段 == 1 并且 "ZoneName" 字段中至少有一个匹配条件列表中的名称列表。如果 "ZoneName" 字段包含条件列表中的至少一个值(例如 "Zone1_Zone3"),它将找到一个匹配项,如果 "ZoneName" 字段包含条件列表中的多个值,它将不会重复计算列表(例如 "Zone1_Zone2"),它不会将部分匹配项匹配到标准列表(例如 "Zone14")。感谢@hpaulj 的帮助!我欢迎任何关于改进方法的进一步评论,特别是在处理速度方面。
import numpy as np
import re
def main():
#sum values from the array if "Flag1"==1, "Flag2"==1, and "ZoneName" includes
#either "Zone1" or "Zone2"
myArray = np.array([(1, 1, 1, u'Zone3', 9.223),
(2, 1, 0, u'Zone2', 17.589),
(3, 1, 1, u'Zone1_Zone2', 26.95),
(4, 0, 1, u'Zone2', 19.367),
(5, 1, 1, u'Zone1_Zone3', 4.395),
(5, 1, 1, u'Zone15', 8.565),
(5, 1, 1, u'Zone2', 7.125),
(5, 1, 0, u'Zone1', 6.395)],
dtype=[('ID', '<i4'), ('Flag1', '<i4'), ('Flag2', '<i4'), ('ZoneName', '<U15'),
('Value', '<f8')])
doneList = [] #empty list to track which zones have been calc'd
values = [] #empty list to store values from loop
criteriaList = ("Zone1", "Zone2")
zones = myArray["ZoneName"]
for criteria in criteriaList:
for zone in zones:
#only calc if the "ZoneName" value from the array includes the criteria
#in the current loop and the record has not already been calc'd
if ((find_word(str(np.char.split(zone,'_')), criteria)) & (zone not in doneList)):
#the key element from previous question
value = myArray[((myArray["Flag1"] == 1) & (myArray["Flag2"] == 1))
& np.in1d(myArray["ZoneName"], zone)]["Value"].sum()
values.append(value)
doneList.append(zone) #Needed to that "Zone1_Zone2" is not double counted
result = sum(values)
print result
def find_word(text, search):
result = re.findall('\b'+search+'\b', text, flags=re.IGNORECASE)
if len(result)>0:
return True
else:
return False
if __name__ == '__main__':
main()