Python 对另一个列表中的列表元素进行编码的最有效方法
假设我有一个排序后的主列表,如下所示:Python 对另一个列表中的列表元素进行编码的最有效方法,python,arrays,performance,numpy,Python,Arrays,Performance,Numpy,假设我有一个排序后的主列表,如下所示: main=[“a”、“b”、“cd”、“e”] 还有一些其他的列表,比如l1=[“a”,“cd”]和l2=[“b”,“cd”]。它还保证单个列表的所有元素,如l1和l2也属于main。并非所有单个列表的长度都必须相同,但所有列表的长度都小于或等于main 现在,对于每个单独的列表,我想创建一个向量来编码main的哪些元素出现在单独的列表中。e、 g.对于l1,我们将得到一个向量(numpy数组)[1,0,1,0],因为main的第一和第三个元素(我可以说是
main=[“a”、“b”、“cd”、“e”]
还有一些其他的列表,比如l1=[“a”,“cd”]
和l2=[“b”,“cd”]
。它还保证单个列表的所有元素,如l1
和l2
也属于main
。并非所有单个列表的长度都必须相同,但所有列表的长度都小于或等于main
现在,对于每个单独的列表,我想创建一个向量来编码main
的哪些元素出现在单独的列表中。e、 g.对于l1
,我们将得到一个向量(numpy数组)[1,0,1,0]
,因为main
的第一和第三个元素(我可以说是“first”和“third”,因为main
已排序)。类似地,对于l2
我们将得到[0,1,1,0]
做这件事的有效方法是什么?我不想采用幼稚的暴力手段,因为那会非常缓慢。是否涉及任何中间numpy转换/操作?我很乐意在这方面得到帮助 您可以使用numpy数组在列表理解中尝试if-else
import numpy as np
#encode presence of elements of a list in another list
def list_contains(mainlist, otherlist):
result = np.array([1 if x in otherlist else 0 for x in mainlist])
return result
你可以跟我核对一下
main = ["a", "b", "cd", "e"]
l1 = ["a", "cd"]
l2 = ["b", "cd"]
#check 1
out1 = list_contains(main, l1)
print(out1) # [1 0 1 0]
type(out1) # numpy.ndarray
#check 2
out2 = list_contains(main, l2)
print(out2) # [0 1 1 0]
type(out2) # numpy.ndarray
您可以使用列表理解:
main = ["a", "b", "cd", "e"]
l1 = ["a", "cd"]
print ([item in l1 for item in main])
输出:
[True, False, True, False]
[1, 0, 1, 0]
或
输出:
[True, False, True, False]
[1, 0, 1, 0]
这是一个带有
np.searchsorted
-
def isin_many(main, L):
# main is the array or list where presence is to be detected
# L is list of lists whose presence is to be detected
main_ar = np.asarray(main)
La = np.concatenate(L)
sidx = np.argsort(main_ar)
idx = sidx[np.searchsorted(main_ar, La, sorter=sidx)]
n = len(L)
out = np.zeros((n,len(main_ar)), dtype=bool)
row = np.repeat(np.arange(n),np.array([len(l) for l in L]))
out[row,idx] = True
return out.view('i1')
输出将是一个2D
数组,其中的每一行将显示主列表中每个单独列表的存在。这主要是一种矢量化方法(唯一的循环是获取单个列表的长度,这在计算上可以忽略不计),因为此类列表的数量很大
样本运行-
In [44]: main = ["a", "b", "cd", "e", "F"]
...: l1 = ["a", "cd"]; l2 = ["b", "cd"]; l3 = ['F']
In [45]: isin_many(main, [l1,l2,l3])
Out[45]:
array([[1, 0, 1, 0, 0], # presence of l1
[0, 1, 1, 0, 0], # presence of l2 and so on ...
[0, 0, 0, 0, 1]], dtype=int8)
我的解决方案使用了numpy isin(它给出了真/假),效率方面,因为在许多情况下,它取决于大小,列表理解在小示例中更快,但在较长的情况下慢得多,如下所示:
import itertools
import string
import random
import numpy as np
main = ["a", "b", "cd", "e"]
l1 = ["a", "cd"]
def f1(main, l):
return [1 if x in l else 0 for x in main]
%%timeit
f1(main, l1)
output: 649 ns ± 15.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%%timeit
np.isin(main, l1)
output:23 µs ± 122 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
还有一个很长的例子:
letters_and_couples = \
[''.join(x) for x in itertools.combinations(string.ascii_lowercase, 2)]+\
[''.join(x) for x in itertools.combinations(string.ascii_lowercase, 1)]
long_main = random.choices(letters_and_couples,k=1000000)
long_l1 = random.choices(letters_and_couples,k=1000)
%%timeit
f1(long_main, long_l1)
output: 5.02 s ± 71.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%%timeit
np.isin(long_main, long_l1)
output: 241 ms ± 1.89 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
正如有人指出的,你可以使用
np.isin
def isin_many_np(main, L):
return np.array([np.isin(main, l) for l in L])
但是,如果您要多次这样做,那么使用字典给出主元素的每个元素的位置会更有效
那么你只需要写以下内容:
def isin_dict(main_d, L):
r = np.zeros(len(main_d), dtype=bool)
for li in L:
r[main_d[li]] = 1
return r
def isin_many_dict(main, L):
main_d = {s:i for i,s in enumerate(main)}
return np.array([isin_dict(main_d, l) for l in L]).view('i1')
这里有一些关于np.isin
和@Divakar答案的基准:
import random
import string
main = sorted([''.join(random.sample(string.ascii_letters, 5)) for i in range(4000)])
L = [random.sample(main, 2000) for i in range(6000)]
%timeit t = isin_many_np(main, L)
6.67 s ± 121 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit r = isin_many_divakar(main, L)
2.17 s ± 50.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit s = isin_many_dict(main, L)
1.27 s ± 11.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
它能有
[“a”、“a”、“a”]
?它的预期输出是什么?通常你会有多少个这样的列表?@Divakar:600000左右。主列表大约有4000个元素。发布的解决方案中有哪一个适合你吗?@Divakar:我使用了numpy.isin(),因为我必须将该功能包装到另一个函数中,而np.isin非常容易实现(内置一行程序),而且看起来非常有效!还有一件事——如果我在主列表和一个单独的列表中都有NaN值怎么办?我已经读到,始终记住NaN值是一种很好的做法,因此我希望忽略(为0赋值)与单个列表中NaN值对应的索引。这可能吗?@ShirishKulhari那么,这是numpy.nan还是'nan'(字符串)或者没有?