2016-11-13 12 views
8

listeleri lverimli Ben ilk <code>[1, 2, 3]</code> ile tek boyutlu nesne dizisi alırsınız

l = [[1, 2, 3], [1, 2]] 

listesini dikkate nan doldurulur asgari içeren diziye listelerinin düzensiz listesini dönüştürmek pozisyon ve ikinci konumda [1, 2].

print(np.array(l)) 

[[1, 2, 3] [1, 2]] 

Şunu istiyorum yerine

print(np.array([[1, 2, 3], [1, 2, np.nan]])) 

[[ 1. 2. 3.] 
[ 1. 2. nan]] 

Ben bir döngü ile yapabilirsiniz, ama hepimiz döngüler ne kadar sevilmeyen biliyoruz

def box_pir(l): 
    lengths = [i for i in map(len, l)] 
    shape = (len(l), max(lengths)) 
    a = np.full(shape, np.nan) 
    for i, r in enumerate(l): 
     a[i, :lengths[i]] = r 
    return a 

print(box_pir(l)) 

[[ 1. 2. 3.] 
[ 1. 2. nan]] 

nasıl bunu yapıyorum hızlı, vectorized bir şekilde?


zamanlama

enter image description here

enter image description here

kurulum fonksiyonları

%%cython 
import numpy as np 

def box_pir_cython(l): 
    lengths = [len(item) for item in l] 
    shape = (len(l), max(lengths)) 
    a = np.full(shape, np.nan) 
    for i, r in enumerate(l): 
     a[i, :lengths[i]] = r 
    return a 

def box_divikar(v): 
    lens = np.array([len(item) for item in v]) 
    mask = lens[:,None] > np.arange(lens.max()) 
    out = np.full(mask.shape, np.nan) 
    out[mask] = np.concatenate(v) 
    return out 

def box_hpaulj(LoL): 
    return np.array(list(zip_longest(*LoL, fillvalue=np.nan))).T 

def box_simon(LoL): 
    max_len = len(max(LoL, key=len)) 
    return np.array([x + [np.nan]*(max_len-len(x)) for x in LoL]) 

def box_dawg(LoL): 
    cols=len(max(LoL, key=len)) 
    rows=len(LoL) 
    AoA=np.empty((rows,cols,)) 
    AoA.fill(np.nan) 
    for idx in range(rows): 
     AoA[idx,0:len(LoL[idx])]=LoL[idx] 
    return AoA 

def box_pir(l): 
    lengths = [len(item) for item in l] 
    shape = (len(l), max(lengths)) 
    a = np.full(shape, np.nan) 
    for i, r in enumerate(l): 
     a[i, :lengths[i]] = r 
    return a 

def box_pandas(l): 
    return pd.DataFrame(l).values 

cevap

6

Bu gibi görünüyor yayını yapıyor cumsum

In [817]: idx=np.r_[0:3, 3:3+2] 
In [818]: idx 
Out[818]: array([0, 1, 2, 3, 4]) 
In [819]: res.flat[idx]=sll 
In [820]: res 
Out[820]: 
array([[ 1., 2., 3.], 
     [ 1., 2., nan]]) 

================

this question'un yakınından biri olan dolgu, NaNs yerine zeros ile doluydu. Buraya ilginç yaklaşımlarile birlikte broadcasting ve boolean-indexing temel alınarak yayınlanmıştır. Yani, sadece bu yüzden gibi bu davayı çözmek için orada benim görevinden bir satır değişiklik yapacağı -

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

Numune run - Üzerinde tümünün yayınlanan yaklaşımların orada birkaç çalışma zamanı sonucu kaydetti

In [32]: l 
Out[32]: [[1, 2, 3], [1, 2], [3, 8, 9, 7, 3]] 

In [33]: boolean_indexing(l) 
Out[33]: 
array([[ 1., 2., 3., nan, nan], 
     [ 1., 2., nan, nan, nan], 
     [ 3., 8., 9., 7., 3.]]) 

In [34]: boolean_indexing(l,-1) 
Out[34]: 
array([[ 1, 2, 3, -1, -1], 
     [ 1, 2, -1, -1, -1], 
     [ 3, 8, 9, 7, 3]]) 

Yararlı olabilecek Q & A.

+0

@piRSquared Anlamayı anlama, haritadan daha iyi performans gösterebilir mi? – Divakar

+0

@piRSquared Ah hayır, sorun yok. Ayrıca, 'map' ile uyumluluk sorunları olabileceğini bilmiyordum. Yani bence adil bir düzenleme. Bazı çalışma zamanı testlerini mutlaka görmek ilginç olurdu! – Divakar

+0

@piRSquared Güzel, gerçekten kapsamlı bir kıyaslama var! Tüm veri boyutlarında net bir kazanan görmediğim için. Yine de iyi yarışmalar. – Divakar

2

böyle Belki bir şey? donanımınız bilmem ama l2 = için 16ms 100 döngüler de anlamı etmeyin [listede (aralık (20)), listenin (aralık (30))] * Ben bu yazabiliriz 10000.

from numpy import nan 


def box(l): 
    max_lenght = len(max(l, key=len)) 
    return [x + [nan]*(max_lenght-len(x)) for x in l] 
+0

Ben gerçekten çok seviyorum (l, anahtar = len) ' – piRSquared

+0

Peki ben gerçekten harita (len, l) ^^ gibi. – Simon

+0

Sorun, numpy'nin jeneratörü genişletmemesidir, bu yüzden gerçek bir karşılaştırma değildir. – dawg

1

bir varsayılan dolu olan alt diziler her biri üzerinde dilim atama şeklidir:

def to_numpy(LoL, default=np.nan): 
    cols=len(max(LoL, key=len)) 
    rows=len(LoL) 
    AoA=np.empty((rows,cols,)) 
    AoA.fill(default) 
    for idx in range(rows): 
     AoA[idx,0:len(LoL[idx])]=LoL[idx] 
    return AoA 

ben ilave Divakar en Boolean Indexingf4 olarak ve zamanlama test eklendi. En azından benim testlerimde, (Python 2.7 ve Python 3.5; Numpy 1.11) en hızlı değil.

from __future__ import print_function 
import numpy as np 
try: 
    from itertools import izip_longest as zip_longest 
except ImportError: 
    from itertools import zip_longest 

def f1(LoL): 
    cols=len(max(LoL, key=len)) 
    rows=len(LoL) 
    AoA=np.empty((rows,cols,)) 
    AoA.fill(np.nan) 
    for idx in range(rows): 
     AoA[idx,0:len(LoL[idx])]=LoL[idx] 
    return AoA 

def f2(LoL): 
    return np.array(list(zip_longest(*LoL,fillvalue=np.nan))).T 

def f3(LoL): 
    max_len = len(max(LoL, key=len)) 
    return np.array([x + [np.nan]*(max_len-len(x)) for x in LoL]) 

def f4(LoL): 
    lens = np.array([len(item) for item in LoL]) 
    mask = lens[:,None] > np.arange(lens.max()) 
    out = np.full(mask.shape,np.nan) 
    out[mask] = np.concatenate(LoL) 
    return out 

if __name__=='__main__': 
    import timeit 
    for case, LoL in (('small', [list(range(20)), list(range(30))] * 1000), 
         ('medium', [list(range(20)), list(range(30))] * 10000), 
         ('big', [list(range(20)), list(range(30))] * 100000), 
         ('huge', [list(range(20)), list(range(30))] * 1000000)): 
     print(case) 
     for f in (f1, f2, f3, f4): 
      print(" ",f.__name__, timeit.timeit("f(LoL)", setup="from __main__ import f, LoL", number=100))  

Baskılar: Muhtemelen

small 
    f1 0.245459079742 
    f2 0.209980010986 
    f3 0.350691080093 
    f4 0.332141160965 
medium 
    f1 2.45869493484 
    f2 2.32307982445 
    f3 3.65722203255 
    f4 3.55545687675 
big 
    f1 25.8796288967 
    f2 26.6177148819 
    f3 41.6916451454 
    f4 41.3140149117 
huge 
    f1 262.429639101 
    f2 295.129109859 
    f3 427.606887817 
    f4 441.810388088 
3

en hızlı liste

Zamanlama izip_longest veya f2 daha hızlı daha büyük listeleri için biraz daha hızlı çoğu listeleri ama (f1 olan) dilim ataması içindir olduğunu gösteriyor sürüm itertools.zip_longest'u kullanır (Py2'de izip_longest olabilir):

In [747]: np.array(list(itertools.zip_longest(*ll,fillvalue=np.nan))).T 
Out[747]: 
array([[ 1., 2., 3.], 
     [ 1., 2., nan]]) 

düz zip üretir:

In [748]: list(itertools.zip_longest(*ll)) 
Out[748]: [(1, 1), (2, 2), (3, None)] 

bir fermuar 'aktarır':

In [751]: list(zip(*itertools.zip_longest(*ll))) 
Out[751]: [(1, 2, 3), (1, 2, None)] 

Genellikle listelerinin (veya listelerinin da bir amacı bir dizi) ile başlanarak, bunun sopa ile hızlı liste yöntemleri. Bir dizi veya veri çerçevesi oluştururken önemli bir ek yük var.

Bu soru ilk defa sorulmadı. Burada şu

How can I pad and/or truncate a vector to a specified length using numpy?

Benim cevabım hem bu zip_longest ve sizin box_pir

Orada düzleştirilmiş dizisi kullanarak hızlı numpy sürümü de, ama ayrıntıları hatırlamıyorum düşünüyorum. Muhtemelen Warren veya Divakar tarafından verildi.

Ben 'düzleştirilmiş' sürümü bu hat boyunca bir şey çalışır düşünüyorum:

In [809]: ll 
Out[809]: [[1, 2, 3], [1, 2]] 
In [810]: sll=np.hstack(ll)  # all values in a 1d array 
In [816]: res=np.empty((2,3)); res.fill(np.nan) # empty target 

değerleri gitmek indeksleri düzleştirilmiş olsun. Bu çok önemli bir adımdır. Burada, r_'un kullanımı yinelemelidir; Hızlı versiyonu muhtemelen kullanır böylece eksik bağlantı >np.arange()

In [897]: lens=np.array([len(i) for i in ll]) 
In [898]: mask=lens[:,None]>np.arange(lens.max()) 
In [899]: mask 
Out[899]: 
array([[ True, True, True], 
     [ True, True, False]], dtype=bool) 
In [900]: idx=np.where(mask.ravel()) 
In [901]: idx 
Out[901]: (array([0, 1, 2, 3, 4], dtype=int32),)