【问题标题】:Match array of strings to 2D array将字符串数组与二维数组匹配
【发布时间】:2020-02-27 00:00:34
【问题描述】:

我有一个 1D 字符串数组 (gene_name_list)。我需要在另一个 2D 数组 (fully_split) 中找到第一个数组的每个字符串都存在的行。当然我可以像这样蛮力解决它:

longest_gene_name = len(max(gene_name_list, key=len))
ensembl_list = np.full((len(gene_name_list)), '', dtype='U{}'.format(longest_gene_name))
for idx, gene_name in enumerate(gene_name_list):  
    for row in fully_split:                       
        if gene_name in row:                      
            ensembl_list[idx] = row[0]

但这需要很长时间,我需要一个更快的解决方案。

row[0] 包含我要映射到的特殊符号。因此,如果找到一个字符串,它将在row[1:] 部分中找到,然后我将使用row[0]。不相关,但要澄清一下。

【问题讨论】:

    标签: python arrays python-2.7 numpy


    【解决方案1】:

    除了执行时间,我认为你发布的蛮力方法与你用文字描述的不相符:

    我需要在另一个二维数组中找到第一个数组的每个字符串存在的行。

    您的代码最多只能找到那里的所有行至少有一个一维数组的字符串存在于二维数组的行中。

    以下代码使用正则表达式执行您在文字中提出的要求。

    import re
    
    pattern = r'*'.join(map(re.escape, np.sort(gene_name_list)))
    rows = [''.join(np.sort(x)) for x in fully_split]
    res = [re.search(pattern, r) for r in rows]
    

    由于顺序不相关,gene_name_list 按字典顺序排序,字符串使用正则表达式特殊字符 '*' 作为分隔符连接。这是将要搜索的模式。
    然后 2D 数组 fully_split 的每一行再次按字典顺序排序,并将字符串连接起来形成一个字符串。对每一行执行正则表达式搜索以检查是否存在匹配项。

    res 是一个列表,对于那些未找到匹配项的行,您将获得 None,而对应的 MatchObject 是找到匹配项。

    这说明了这个概念。为了更接近您的预期结果(存储行的第一个元素的位置),请将最后一行替换为:

    res = [l[0] if re.search(pattern, r) else None for r, l in zip(rows, fully_split)]
    

    【讨论】:

      【解决方案2】:

      根据您的描述,我做了几个假设:
      - 二维数组是矩形的(即不是dtype=object),否则 NumPy 性能将毫无用处。
      - len(fully_split) == len(gene_name_list) 因为您的代码示例有 ensembl_list[idx] = row[0]idx 派生自 gene_name_list

      >>> gene_name_list = np.array('a bb c d eee'.split())
      
      >>> fully_split = np.array([
      ...     'id1 a bb c d eee'.split(), # yes
      ...     'id2 f g hh iii j'.split(),
      ...     'id3 kk ll a nn o'.split(), # yes
      ...     'id4 q rr c t eee'.split(), # yes
      ...     'id5 v www xx y z'.split()
      ... ])
      
      >>> longest_gene_name = len(max(gene_name_list, key=len))
      
      >>> dtype = 'U{}'.format(longest_gene_name)
      
      >>> ensembl_list = np.zeros_like(gene_name_list, dtype=dtype)
      
      >>> mask = np.isin(fully_split, gene_name_list).any(axis=1)
      
      >>> ensembl_list[mask] = fully_split[mask, 0]
      
      >>> ensembl_list
      array(['id1', '', 'id3', 'id4', ''], dtype='<U3')
      

      【讨论】:

      • 是的,这就是答案。唯一的问题是np.isin 在早期的numpy 版本中不存在,而我正在使用python 2.7。然后用in1d 以某种方式重写它是有意义的......
      • 查看 source codenp.isin 几乎是一个 1-liner 来实现(假设在 v1.8.0 中引入的 invert 参数在 python 2.7 中可用)。
      猜你喜欢
      • 2019-09-04
      • 2021-12-07
      • 2019-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多