Python/Numpy:向量化行元素与条件的组合

Python/Numpy: Vectorizing the combining of row elements with conditions

有没有办法在特定条件下对行元素的组合进行矢量化?

条件:

  1. 删除空元素
  2. 包含 1 个以上非空元素的行由“\n”分隔

注意 a) 我的数组有可变数量的行和列,并且会变得非常大,因此我对这里的矢量化感兴趣 b) 每个非空字符串元素以 '$' 字符开头

arr = np.array([       
        ['',  '',  '$c'],
        ['',  '$b', '' ],
        ['',  '$b', '$c'],
        ['$a', '',  '' ],
        ['$a', '',  '$c'],
        ['$a', '$b', '' ],
        ['$a', '$b', '$c']
    ], dtype='U1')

想要的结果:

res = [       
        ['$c'],              # <-- reduce to single char element
        ['$b'],              # <-- reduce to single char element
        ['$b\n$c'],           # <-- combine char elements with '\n' delimiter
        ['$a'],              # <-- reduce to single char element
        ['$a\n$c'],           # <-- combine char elements with '\n' delimiter
        ['$a\n$b'],           # <-- combine char elements with '\n' delimiter
        ['$a\n$b\n$c']         # <-- combine char elements with '\n' delimiter
    ]

任何对实现预期最终结果的矢量化方法的见解都将不胜感激。提前谢谢你。

更新:

由于需求的差异, 的建议答案并不最适合我的用例。请参阅下面已接受的答案。

即使在您更新的情况下,我也不会为此推荐基于 numpy 的解决方案,而是使用。

arr = arr.tolist()
empty_removed = [[el for el in row if el != ''] for row in arr]
result = ["\n".join(row) for row in empty_removed]

即使是您的小示例,您也可以在评论中看到与您的解决方案相比显着的速度差异:

# array solution
timeit.timeit("['\n'.join(sub[sub != '']) for sub in arr]", "from __main__ import arr")
# time: 13.177253899999982

# list solution (with initial cast to list)
timeit.timeit("['\n'.join(row) for row in [[el for el in row if el != ''] for row in arr.tolist()]]", "from __main__ import arr") 
# time: 1.9387359000000117

# list solution (if you can avoid the array in the beginning)
timeit.timeit("['\n'.join(row) for row in [[el for el in row if el != ''] for row in arr_list]]", "from __main__ import arr_list")
# time 1.4084819999999922

如果你以后想把它转换成一个numpy数组来使用np.tilenp.repeat,这当然可以做到。但是,我会测试这是否不会导致您的管道出现类似的减速。


旧答案,仅供参考

我建议您不要使用 NumPy 数组,而改用简单明了的列表理解:

arr = arr.tolist() # if you can avoid array creation, even better
result = ['\n'.join(sub) for sub in [''.join(sub) for sub in arr]]
# or if you need the list wrapping the individual elements
result2 = [['\n'.join(sub)] for sub in [''.join(sub) for sub in arr]]

这样做的原因有点复杂。它的要点是 numpy 不能像在 dtype=np.number 上那样加速在 dtype=object 上的数组操作。您可以获得花式索引(高级索引是我现在认为的名称)和基于元组的索引同样的便利,但实际性能无法比较。你可以在这里得到一些直觉: