Python/Numpy:向量化行元素与条件的组合
Python/Numpy: Vectorizing the combining of row elements with conditions
有没有办法在特定条件下对行元素的组合进行矢量化?
条件:
- 删除空元素
- 包含 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.tile
和np.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
上的数组操作。您可以获得花式索引(高级索引是我现在认为的名称)和基于元组的索引同样的便利,但实际性能无法比较。你可以在这里得到一些直觉:
有没有办法在特定条件下对行元素的组合进行矢量化?
条件:
- 删除空元素
- 包含 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.tile
和np.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
上的数组操作。您可以获得花式索引(高级索引是我现在认为的名称)和基于元组的索引同样的便利,但实际性能无法比较。你可以在这里得到一些直觉: