为数组中的每个唯一元素创建布尔掩码
我有一个包含数字的列表。我想为此列表的每个唯一元素创建一个此列表(或数组,无关紧要)的布尔掩码。为数组中的每个唯一元素创建布尔掩码
在下面的示例中,我想创建四个长度为len(labels)
的蒙版。所述第一掩模具有在True
位置i
,如果labels[i]==0
,第二个在i
位置具有True
,如果labels[i]==1
等
我试图与熊猫和在一个循环中.isin
方法做到这一点。然而,这对于我的目的来说太慢了,因为这在我的算法中被多次调用,并且标签列表可能很长,所以循环无效。我怎样才能让这个更快?
labels = [0,0,1,1,3,3,3,1,2,1,0,0]
d = dict()
y = pd.Series(labels)
for i in set(labels):
d[i] = y.isin([i])
方法1
使用list
和set
In [989]: {x: [x==l for l in labels] for x in set(labels)}
Out[989]:
{0: [True, True, False, False, False, False, False, False, False, False, True, True],
1: [False, False, True, True, False, False, False, True, False, True, False, False],
2: [False, False, False, False, False, False, False, False, True, False, False, False],
3: [False, False, False, False, True, True, True, False, False, False, False, False]}
如果你想把它当作dataframe
In [994]: pd.DataFrame({x: [x==l for l in labels] for x in set(labels)})
Out[994]:
0 1 2 3
0 True False False False
1 True False False False
2 False True False False
3 False True False False
4 False False False True
5 False False False True
6 False False False True
7 False True False False
8 False False True False
9 False True False False
10 True False False False
11 True False False False
方法2
使用pd.get_dummies
,如果你反正series
可以
In [997]: pd.get_dummies(y).astype(bool)
Out[997]:
0 1 2 3
0 True False False False
1 True False False False
2 False True False False
3 False True False False
4 False False False True
5 False False False True
6 False False False True
7 False True False False
8 False False True False
9 False True False False
10 True False False False
11 True False False False
基准
小
In [1002]: len(labels)
Out[1002]: 12
In [1003]: %timeit pd.get_dummies(y).astype(bool)
1000 loops, best of 3: 476 µs per loop
In [1004]: %timeit pd.DataFrame({x: [x==l for l in labels] for x in set(labels)})
1000 loops, best of 3: 580 µs per loop
In [1005]: %timeit pd.DataFrame({x : (y == x) for x in y.unique()})
1000 loops, best of 3: 1.15 ms per loop
大
In [1011]: len(labels)
Out[1011]: 12000
In [1012]: %timeit pd.get_dummies(y).astype(bool)
1000 loops, best of 3: 875 µs per loop
In [1013]: %timeit pd.DataFrame({x: [x==l for l in labels] for x in set(labels)})
100 loops, best of 3: 4.97 ms per loop
In [1014]: %timeit pd.DataFrame({x : (y == x) for x in y.unique()})
1000 loops, best of 3: 1.32 ms per loop
可以使用pd.Series.unique
的字典解析里:
In [211]: pd.DataFrame({x : (y == x) for x in y.unique()})
Out[211]:
0 1 2 3
0 True False False False
1 True False False False
2 False True False False
3 False True False False
4 False False False True
5 False False False True
6 False False False True
7 False True False False
8 False False True False
9 False True False False
10 True False False False
11 True False False False
列标题对应于该系列中的独特价值。
为什么将字典包装在DataFrame中是一个好主意? – Merlin1896
@ Merlin1896为了向你展示整齐的输出:)你不需要这样做。 –
啊,明白了! :) – Merlin1896
创建一个False
值的数组。遍历groupby
以获取标签的索引位置,并将其设置为True
。
d = {}
empty_labels = np.array([False] * len(labels))
for label, group in pd.DataFrame(labels, columns=['labels']).groupby('labels'):
d[label] = empty_labels.copy()
d[label][group] = True
>>> d
{0: array([ True, False, False, False, False, False, False, False, False,
False, False, False], dtype=bool),
1: array([False, True, False, False, False, False, False, False, False,
False, False, False], dtype=bool),
2: array([False, False, True, False, False, False, False, False, False,
False, False, False], dtype=bool),
3: array([False, False, False, True, False, False, False, False, False,
False, False, False], dtype=bool)}
速度应该与pd.get_dummies
相等。
你可以使用statsmodels.tools.tools.categorical
,这应该是相当快,尤其是如果你已经有一个NumPy数组可以使用。
categorical(np.array(labels), drop=True).astype(bool)
如果希望得到的阵列中的每列和其相应的标签之间的显式映射,传dictnames=True
到category
。
演示
>>> from statsmodels.tools.tools import categorical
>>> labels = np.array([0,0,1,1,3,3,3,1,2,1,0,0])
>>> categorical(labels, drop=True).astype(bool)
array([[ True, False, False, False],
[ True, False, False, False],
[False, True, False, False],
[False, True, False, False],
[False, False, False, True],
[False, False, False, True],
[False, False, False, True],
[False, True, False, False],
[False, False, True, False],
[False, True, False, False],
[ True, False, False, False],
[ True, False, False, False]], dtype=bool)
>>> res, d = categorical(np.array(labels), drop=True, dictnames=True)
>>> d
{0: 0, 1: 1, 2: 2, 3: 3}
粗略的基准(假设已经NumPy的阵列)
您的数据集:
>>> %timeit categorical(labels, drop=True).astype(bool)
14.1 µs ± 519 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
大数据集:labels = np.random.randint(0, 4, 10000)
%timeit categorical(labels, drop=True).astype(bool)
360 µs ± 9.08 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
这似乎没有产生所需的输出格式。尤其是,如果标签数组在数字中不连续,例如。标签= [1,1,0,1,5,6,12,,12,4,5]。 – Merlin1896
@ Merlin1896请问大纲在这种情况下输出格式有什么问题?对我来说,它看起来和我所预期的一样。 – miradulo
With labels = np.array([0,0,2,3,2,12])a = categorical(labels,drop = True).astype(bool)的输出不会给我对原始标签的引用。 a [:,0]是标签0所需的输出,但a [:,1]是标签2的输出。 – Merlin1896
这样写for循环比我的方式更快吗? – Merlin1896
它往往很快。请阅读https://stackoverflow.com/q/30245397 – Zero