2016-07-27 42 views
15

Die implizite Umwandlung einer Sequenz von Python variabler Länge Listen in einem Array NumPy die Anordnung bewirken, von Objekttyp sein.Konvertieren Python Sequenz NumPy Array, fehlende Werte Füllung

v = [[1], [1, 2]] 
np.array(v) 
>>> array([[1], [1, 2]], dtype=object) 

Der Versuch, eine andere Art zu zwingen, wird eine Ausnahme verursachen:

np.array(v, dtype=np.int32) 
ValueError: setting an array element with a sequence. 

Was ist der effizienteste Weg, um eine dichte NumPy Array vom Typ int32 zu bekommen, durch Füllen der „fehlenden“ Werte mit einer bestimmten Platzhalter?

Aus meiner Probensequenz v, würde Ich mag so etwas bekommen, wenn 0 der Platzhalter

array([[1, 0], [1, 2]], dtype=int32) 

Antwort

13

können Sie itertools.zip_longest verwenden:

import itertools 
np.array(list(itertools.zip_longest(*v, fillvalue=0))).T 
Out: 
array([[1, 0], 
     [1, 2]]) 

Hinweis: Für Python 2 ist es itertools.izip_longest.

+3

Das scheint wirklich gut zu sein, wenn die Größenvariation innerhalb der Listenelemente groß ist, basierend auf einem schnellen Laufzeittest für einen großen Datensatz. – Divakar

11

Pandas und sein DataFrame er behandelt schön mit fehlenden Daten ist.

import numpy as np 
import pandas as pd 

v = [[1], [1, 2]] 
print(pd.DataFrame(v).fillna(0).values.astype(np.int32)) 

# array([[1, 0], 
#  [1, 2]], dtype=int32) 
+2

Dies ist ideal für Daten mit weniger Größenvariation, wirklich gute Lösung! – Divakar

2
max_len = max(len(sub_list) for sub_list in v) 

result = np.array([sub_list + [0] * (max_len - len(sub_list)) for sub_list in v]) 

>>> result 
array([[1, 0], 
     [1, 2]]) 

>>> type(result) 
numpy.ndarray 
10

Hier ist eine fast * vektorisiert boolean-Indizierung basierten Ansatz, den ich in einigen anderen Stellen verwendet haben -

def boolean_indexing(v): 
    lens = np.array([len(item) for item in v]) 
    mask = lens[:,None] > np.arange(lens.max()) 
    out = np.zeros(mask.shape,dtype=int) 
    out[mask] = np.concatenate(v) 
    return out 

Probelauf

In [27]: v 
Out[27]: [[1], [1, 2], [3, 6, 7, 8, 9], [4]] 

In [28]: out 
Out[28]: 
array([[1, 0, 0, 0, 0], 
     [1, 2, 0, 0, 0], 
     [3, 6, 7, 8, 9], 
     [4, 0, 0, 0, 0]]) 

* Bitte beachten Sie, dass diese geprägt als fast vektorisiert, weil die einzige hier durchgeführte Schleife am Anfang ist, wo wir die Längen der Listenelemente erhalten. Aber dieser Teil, der nicht so rechenintensiv ist, sollte minimale Auswirkungen auf die Gesamtlaufzeit haben.

Runtime Test

In diesem Abschnitt I DataFrame-based solution by @Alberto Garcia-Raboso bin Timing, itertools-based solution by @ayhan, wie sie scheinen gut und die boolean-Indizierung eine von diesem Posten für einen relativ größeren Datensatz mit drei Ebenen der Größenvariation über die Basis maßstab Listenelemente.

Fall # 1: Größere Grßenvariation

In [44]: v = [[1], [1,2,4,8,4],[6,7,3,6,7,8,9,3,6,4,8,3,2,4,5,6,6,8,7,9,3,6,4]] 

In [45]: v = v*1000 

In [46]: %timeit pd.DataFrame(v).fillna(0).values.astype(np.int32) 
100 loops, best of 3: 9.82 ms per loop 

In [47]: %timeit np.array(list(itertools.izip_longest(*v, fillvalue=0))).T 
100 loops, best of 3: 5.11 ms per loop 

In [48]: %timeit boolean_indexing(v) 
100 loops, best of 3: 6.88 ms per loop 

Fall # 2: Lesser Grßenvariation

In [49]: v = [[1], [1,2,4,8,4],[6,7,3,6,7,8]] 

In [50]: v = v*1000 

In [51]: %timeit pd.DataFrame(v).fillna(0).values.astype(np.int32) 
100 loops, best of 3: 3.12 ms per loop 

In [52]: %timeit np.array(list(itertools.izip_longest(*v, fillvalue=0))).T 
1000 loops, best of 3: 1.55 ms per loop 

In [53]: %timeit boolean_indexing(v) 
100 loops, best of 3: 5 ms per loop 

Fall # 3: größere Anzahl von Elementen (100 max) pro Listenelement

In [139]: # Setup inputs 
    ...: N = 10000 # Number of elems in list 
    ...: maxn = 100 # Max. size of a list element 
    ...: lens = np.random.randint(0,maxn,(N)) 
    ...: v = [list(np.random.randint(0,9,(L))) for L in lens] 
    ...: 

In [140]: %timeit pd.DataFrame(v).fillna(0).values.astype(np.int32) 
1 loops, best of 3: 292 ms per loop 

In [141]: %timeit np.array(list(itertools.izip_longest(*v, fillvalue=0))).T 
1 loops, best of 3: 264 ms per loop 

In [142]: %timeit boolean_indexing(v) 
10 loops, best of 3: 95.7 ms per loop 

Für mich scheint es itertools.izip_longest geht es ziemlich gut! gibt es keinen klaren Gewinner, müsste aber von Fall zu Fall entschieden werden!

+0

Ihre Methode scheint schneller in meinen Tests :) http://i.imgur.com/W8Q2zF8.png – ayhan

+0

@ayhan Hmm kann das nicht auf meiner Python 2-Version ausführen. Könnte es meine NumPy Version 1.11.1 sein? – Divakar

+2

Ich denke, dass alle Methoden über "v" iterieren, aber wenn die Listen in v größer werden, wird Ihre Methode schneller. Ich habe es mit n = 10^3, m = 10^4 versucht und es war 5 mal schneller. Ich habe 1.11.1 in Python 3, aber die Ergebnisse sind sehr ähnlich zu Python 2.7 numpy 1.10.4 – ayhan

1

Hier ist eine allgemeine Art und Weise:

>>> v = [[1], [2, 3, 4], [5, 6], [7, 8, 9, 10], [11, 12]] 
>>> max_len = np.argmax(v) 
>>> np.hstack(np.insert(v, range(1, len(v)+1),[[0]*(max_len-len(i)) for i in v])).astype('int32').reshape(len(v), max_len) 
array([[ 1, 0, 0, 0], 
     [ 2, 3, 4, 0], 
     [ 5, 6, 0, 0], 
     [ 7, 8, 9, 10], 
     [11, 12, 0, 0]], dtype=int32)