2017-08-28 3 views
1

J'ai un vecteur de booléen avec la dimension 1 * n, supposons n = 6. Je souhaite le remplacer par une matrice n * 2. Pour chaque élément de vec, s'il est 1, alors dans la matrice, la ligne correspondante doit être [1, 0]; s'il s'agit de 0, la ligne correspondante doit être [0, 1]. Ainsi, la matrice résultante doit êtreapproche vectorisée pour changer tableau booléen 1 dimension en 2 dimensions, python 3

matr = [[1, 0], 
     [0, 1], 
     [1, 0], 
     [0, 1], 
     [0, 1], 
     [1, 0]] 

Pour convertir le vecteur à la matrice, il me faut une approche élégante vectorisée (évitant for-loops), car dans le cas réel n serait beaucoup plus grande que 6. La raison de cette conversion est pour la classification d'apprentissage automatique. Le vec fait référence à binary classification, et le matr sera utilisé pour categorical classification. Peut-être que cette information peut rendre ma question plus spécifique.

J'utilise Python 3, numpy/scipy, sklearn.

Quelqu'un peut-il m'aider avec? Merci.

Répondre

3

En supposant que vec est un numpy.array:

vec = np.array([1, 0, 1, 0, 0, 1]) 

Vous pouvez ensuite empiler colonne sage avec elle-même au niveau du bit XOR pour inverser les valeurs de 0-> 1 et 1-> 0, par exemple:

out = np.stack((vec, vec^1), axis=1) 

vous donne:

array([[1, 0], 
     [0, 1], 
     [1, 0], 
     [0, 1], 
     [0, 1], 
     [1, 0]]) 

Merci à Warren Weckesser pour ce qui suggère une approche plus rapide de la radiodiffusion a comment:

vec[:,None]^[0, 1] 

timings de base:

In [33]: %timeit np.stack((a, a^1), axis=1) 
15.6 µs ± 199 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) 

In [34]: %timeit a[:,None]^[0, 1] 
7.4 µs ± 45.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 
+0

Vous pouvez éliminer le besoin de 'stack' avec quelque chose comme' vec [:, None]^[0, 1] '. –

+0

@Warren réflexion fantastique ... c'est aussi à partir d'un simple timeit ~ 50% plus rapide - voulez-vous afficher cela comme une réponse? –

+0

@aura J'irais pour l'approche de Warren. Ce n'est pas aussi évident que ce que ça fait, mais c'est beaucoup plus rapide et produit aussi le résultat désiré. –

2

est ici une approche avec l'indexation de tableau. Fondamentalement, nous utiliserions un tableau 2D avec deux sous-tableaux pour 0 et 1 mappage de vec. Pour la partie indexation, np.take est très efficace pour de tels indices répétés. La mise en œuvre ressemblerait à quelque chose comme ça -

mapping = np.array([[0,1],[1,0]]) 
out = np.take(mapping, vec, axis=0) 

run échantillon -

In [115]: vec = np.array([1, 0, 1, 0, 0, 1]) 

In [116]: np.take(np.array([[0,1],[1,0]]), vec, axis=0) 
Out[116]: 
array([[1, 0], 
     [0, 1], 
     [1, 0], 
     [0, 1], 
     [0, 1], 
     [1, 0]]) 

Runtime test plus grand ensemble de données -

In [108]: vec = np.random.randint(0,2,(10000000)) 

# @Jon Clements's soln 
In [109]: %timeit np.stack((vec, vec^1), axis=1) 
10 loops, best of 3: 50.2 ms per loop 

# @Warren Weckesser's suggestion soln 
In [110]: %timeit vec[:,None]^[0, 1] 
10 loops, best of 3: 90 ms per loop 

# Proposed in this post 
In [111]: %timeit np.take(np.array([[0,1],[1,0]]), vec, axis=0) 
10 loops, best of 3: 31 ms per loop 
+0

Okay ... essayons encore ça ... J'obtiens pile: 2.44ms, diffusion: 3.12ms et prise: 1.06ms donc - ressemble à une amélioration supplémentaire :) –

+0

@JonClements Bon pour obtenir les résultats confirmant, merci! – Divakar