1

我有一个关于我在这里发布的后续问题。在那个问题中,我试图根据多个条件对一个 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)
4

2 回答 2

0

('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——大约是 1/3 的速度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,而且只有 1/2 的速度find。需要改进模式以区分Zone1_Zone14,但使用 很容易re

于 2015-11-17T17:37:37.260 回答
0

这是我的问题的一个有效解决方案,但速度很慢(实际数组有> 200,000条记录,并且有超过50个“区域”)它基于多个字段对来自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()
于 2015-11-17T19:20:19.387 回答