Python 为数组中的每个唯一元素创建布尔掩码

Python 为数组中的每个唯一元素创建布尔掩码,python,pandas,optimization,Python,Pandas,Optimization,我有一张有数字的单子。我想为列表中的每个唯一元素创建一个列表(或数组,无所谓)的布尔掩码 在下面的示例中,我想创建四个长度为len(标签)的遮罩。第一个掩码在位置i处具有True,如果标签[i]==0,第二个掩码在位置i处具有True,如果标签[i]==1等 我尝试使用pandas和循环中的.isin方法来实现这一点。然而,这对于我来说太慢了,因为在我的算法中,这被调用了很多次,标签列表可能很长,因此循环无效。我怎样才能使它更快 labels = [0,0,1,1,3,3,3,1,2,1,0,0

我有一张有数字的单子。我想为列表中的每个唯一元素创建一个列表(或数组,无所谓)的布尔掩码

在下面的示例中,我想创建四个长度为
len(标签)
的遮罩。第一个掩码在位置
i
处具有
True
,如果
标签[i]==0
,第二个掩码在位置
i
处具有
True
,如果
标签[i]==1

我尝试使用pandas和循环中的
.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

使用
列表
设置

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]}
如果您想将其作为数据帧

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
,如果你仍然是
系列
你可以

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

基准

小的

大的


创建一个
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)}

速度应该与P.GETY-Dimes>

,你可以使用它,这应该相当快,尤其是如果你已经有一个NUMPY数组工作的话。p>

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)

这种编写for循环的方式比我的方式快吗?这似乎不会产生所需的输出格式。特别是,如果标签数组中的数字不是连续的,例如标签=[1,1,0,1,5,6,12,12,4,5]。@Merlin1896在这种情况下,您能概述一下输出格式的错误吗?对我来说,它看起来就像我期望的那样。对于labels=np.array([0,0,2,3,2,12]),a=category(labels,drop=True)的输出。astype(bool)不会给我对原始标签的引用。a[:,0]是标签0所需的输出,但a[:,1]是标签2的输出。@Merlin1896请查看我的编辑,我意识到有一个
dictnames
param to
category
可以帮助您获得我认为您需要的映射。如果需要反向映射,只需使用
{v:k表示k,v表示d.items()}
>>> 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}
>>> %timeit categorical(labels, drop=True).astype(bool)
14.1 µs ± 519 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit categorical(labels, drop=True).astype(bool)
360 µs ± 9.08 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)