2017-01-26 4 views
6

ich ein Array von ganzen Zahlen von Länge 150 und die ganzen Zahlen im Bereich von 1 bis 3 ist beispielsweiseein Array von ganzen Zahlen zu einem „Vektor“ Konvertieren

array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
     1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
     2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 
     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 
     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]) 

Ich mag/Karte konvertieren/umwandeln

1 to [0,0,1] 

2 to [0,1,0] 

3 to [1,0,0] 

Gibt es eine effiziente Möglichkeit, das zu tun?

So wird die Ausgänge sind wie

[0,0,1],[0,0,1],[0,0,1]...[1,0,0] 
+0

Haben Sie versucht, Wörterbücher verwenden? –

+0

hmm .. Ich glaube, ich habe es versucht, aber kann ich es einem Array zuordnen? [0,0,1] ... und so weiter. Ich versuchte es, aber ohne Erfolg. Vielleicht habe ich es falsch implementiert – misheekoh

+0

Ich denke, Sie können –

Antwort

7

Zuerst Sie als Array kodieren Transformation (mit einem Dummy ersten Elemente, da Sie nicht 0 ordnen):

>>> mapping = np.array([[0,0,0],[0,0,1],[0,1,0],[1,0,0]]) 

Dann ist es trivial:

>>> arr = np.array([1,1,2,3,3,3]) 
>>> mapping[arr] 
array([[0, 0, 1], 
     [0, 0, 1], 
     [0, 1, 0], 
     [1, 0, 0], 
     [1, 0, 0], 
     [1, 0, 0]]) 
+0

sehr erstaunliche Verwendung der erweiterten Indexierung. – MSeifert

3

Wie wäre es damit?

a = [1, 1, 1, 2, 2, 2, 3, 3, 3] 
b = [] 

for i in a: 
    if i == 1: 
     b.append([0,0,1]) 
    elif i == 2: 
     b.append([0,1,0]) 
    else: 
     b.append([1,0,0]) 

print(b) 

#[[0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 1, 0], [0, 1, 0], [0, 1, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0]] 
3

ich tun würde, es Wörterbücher und Liste Verständnis, wie diese

''' 
This is a dictionary to map your values 
''' 
my_dict = { 
    1:[0,0,1], 
    2:[0,1,0], 
    3:[1,0,0] 
    } 
''' 
This is your original Array 
''' 
my_array = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
     1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
     2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 
     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 
     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] 
''' 
Use list comprehention to map one to another 
''' 
my_new_array = [my_dict[i] for i in my_array] 
+1

Aber fast sicher nicht sehr effizient im Vergleich zu jeder numpigen Lösung. Dies ist jedoch wahrscheinlich die schnellste Python-Lösung! – MSeifert

+0

Danke Shiping: D. Nun, MSeifert, Wörterbücher sind O (1) und Listenverstehen ist O (n), also ist mein Algorithmus O (n), denn diese Art von Operation wird nicht viel schneller als das. Numpy könnte mehr Speicher effizient sein, aber Sie verlieren all das, wenn Sie import numpy eingeben –

+2

@ JoãoAreias: Big-O ist nicht relevant - eine NumPy-Lösung wird eine Diktatlösung absolut zerstören, wenn die Daten sogar mäßig groß sind. OP verwendet NumPy bereits, daher ist der Import bereits erfolgt. –

1

Lösung mit Liste Verständnis mit, wenn Sie Bereich von 1 bis 3 haben:

>>> [([0,0,1] if x==1 else [0,1,0] if x==2 else [1,0,0]) for x in c] 

[[0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0]] 

Dies ist mehr pythisch und schnell.

6

Sie können tatsächlich vergleichen sie einfach und legen Sie die entsprechenden Objekte:

>>> # a bit shorter so it's easier to demonstrate 
>>> arr = np.array([1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]) 
>>> arr2 = np.zeros([arr.size, 3], arr.dtype) 
>>> arr2[:, 0] = arr == 3 
>>> arr2[:, 1] = arr == 2 
>>> arr2[:, 2] = arr == 1 

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

Sie sagten, Sie in Effizienz interessiert waren, so habe ich ein paar Timings:

my_dict = { 
    1:[0,0,1], 
    2:[0,1,0], 
    3:[1,0,0] 
    } 

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

def mine(arr): 
    arr2 = np.zeros([arr.size, 3], arr.dtype) 
    arr2[:, 0] = arr == 3 
    arr2[:, 1] = arr == 2 
    arr2[:, 2] = arr == 1 
    return arr2 

def JoaoAreias(arr): 
    return [my_dict[i] for i in arr] 

def JohnZwinck(arr): 
    return mapping[arr] 

def Divakar(arr): 
    return (arr == np.arange(3,0,-1)[:,None]).T.astype(np.int8) 

def Divakar2(arr): 
    return np.take(mapping, arr,axis=0) 

arr = np.random.randint(1, 4, (150)) 
np.testing.assert_array_equal(mine(arr), JohnZwinck(arr)) 
np.testing.assert_array_equal(mine(arr), mine_numba(arr)) 
np.testing.assert_array_equal(mine(arr), Divakar(arr)) 
np.testing.assert_array_equal(mine(arr), Divakar2(arr)) 
%timeit mine(arr)  # 5. - 10000 loops, best of 3: 48.3 µs per loop 
%timeit JoaoAreias(arr) # 6. - 10000 loops, best of 3: 179 µs per loop 
%timeit JohnZwinck(arr) # 3. - 10000 loops, best of 3: 24.1 µs per loop 
%timeit mine_numba(arr) # 1. - 100000 loops, best of 3: 6.02 µs per loop 
%timeit Divakar(arr)  # 4. - 10000 loops, best of 3: 34.2 µs per loop 
%timeit Divakar2(arr) # 2. - 100000 loops, best of 3: 13.5 µs per loop 

arr = np.random.randint(1, 4, (10000)) 
np.testing.assert_array_equal(mine(arr), JohnZwinck(arr)) 
np.testing.assert_array_equal(mine(arr), mine_numba(arr)) 
np.testing.assert_array_equal(mine(arr), Divakar(arr)) 
np.testing.assert_array_equal(mine(arr), Divakar2(arr)) 
%timeit mine(arr)  # 4. - 1000 loops, best of 3: 201 µs per loop 
%timeit JoaoAreias(arr) # 6. - 100 loops, best of 3: 10.2 ms per loop 
%timeit JohnZwinck(arr) # 5. - 1000 loops, best of 3: 455 µs per loop 
%timeit mine_numba(arr) # 1. - 10000 loops, best of 3: 103 µs per loop 
%timeit Divakar(arr)  # 3. - 10000 loops, best of 3: 155 µs per loop 
%timeit Divakar2(arr) # 2. - 10000 loops, best of 3: 146 µs per loop 

Es hängt also auf deiner Datengröße welche zu bevorzugen ist, wenn sie eher klein ist als @JohnZwinck hat die schnellste Lösung, bei "größeren" Datensätzen gewinnt mein Ansatz. :)


Eigentlich, wenn du gehst, etwas zu verwenden, wie (oder alternativly cython oder ähnlich) Sie alle anderen Ansätze schlagen:

import numba as nb 

@nb.njit 
def mine_numba(arr): 
    arr2 = np.zeros((arr.size, 3), arr.dtype) 
    for idx in range(arr.size): 
     item = arr[idx] 
     if item == 1: 
      arr2[idx, 2] = 1 
     elif item == 2: 
      arr2[idx, 1] = 1 
     else: 
      arr2[idx, 0] = 1 
    return arr2 
+0

Schöne Zeiten. Du kannst deine Version sogar etwas schneller machen, indem du 'order = 'F'' zum' nullen() 'Aufruf hinzufügst. Das macht es effizienter, wenn Sie die Werte spaltenweise zuweisen. –

+0

Hmm! Sehr schön. Da die Daten, an denen ich arbeite, klein sind, ist Johns eine ausreichend. Aber ich werde es mir merken! – misheekoh

+0

@JohnZwinck Ich habe das tatsächlich versucht (oder etwas Ähnliches: Ich habe ein transponiertes Array erstellt und die 'np.transpose' zurückgegeben), aber für kleine Datenmengen ist das marginal langsamer (während es auf großen Arrays um 10-20% schneller ist). Die numba Lösung (wahrscheinlich Overkill :-)) war viel interessanter ** und ** schneller. – MSeifert

2

Ansatz # 1:NumPy broadcasting Verwendung -

(arr == np.arange(3,0,-1)[:,None]).T.astype(np.int8) 

Ansatz # 2: Ähnlich @John Zwinck 's Idee der Indexierung, aber mit np.take entlang der ersten Achse, die hier hilft, weil die Indizes sind enorm wiederholt. Diese sind in this previous post zeitgesteuert.

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

Runtime Test @ MSeifert Benchmark-Setup mit -

In [85]: arr = np.random.randint(1, 4, (10000)) 

In [86]: %timeit MSeifert(arr) 
    ...: %timeit JoaoAreias(arr) 
    ...: %timeit JohnZwinck(arr) 
    ...: 
10000 loops, best of 3: 105 µs per loop 
100 loops, best of 3: 2.97 ms per loop 
1000 loops, best of 3: 240 µs per loop 

# Approach #1 
In [87]: %timeit (arr == np.arange(3,0,-1)[:,None]).T.astype(np.int8) 
10000 loops, best of 3: 44.1 µs per loop 

# Approach #2 
In [88]: %timeit np.take(mapping, arr,axis=0) 
10000 loops, best of 3: 73 µs per loop 
Verwandte Themen