2014-09-06 45 views
20

Geniş bir veri çerçevem ​​var (birkaç milyon satır).Pandaların ardışık parçalarının verimli bir şekilde nasıl kopyalanacağı

Üzerinde bir grup çalışması yapmak istiyorum, ancak hangi gruba gittiğine karar vermek için tek tek satırların belirli bir özelliğini kullanmak yerine, yalnızca ardışık ardışık (tercihen eşit büyüklükte) satır alt kümeleriyle gruplamak istiyorum .

Kullanım durumu: IPython'daki bir paralel harita üzerinden her satıra bir işlev uygulamak istiyorum. Hangi satırların hangi arka uç motora gittiği önemli değil, çünkü işlev bir seferde bir sıraya dayalı bir sonuç hesaplar.

# Generate a number from 0-9 for each row, indicating which tenth of the DF it belongs to 
max_idx = dataframe.index.max() 
tenths = ((10 * dataframe.index)/(1 + max_idx)).astype(np.uint32) 

# Use this value to perform a groupby, yielding 10 consecutive chunks 
groups = [g[1] for g in dataframe.groupby(tenths)] 

# Process chunks in parallel 
results = dview.map_sync(my_function, groups) 

Ama bu çok uzun soluklu görünüyor ve eşit büyüklükte parçalar garanti etmez:

böyle bir şey ile geldim; (. Kavramsal olarak en az gerçekte vectorized oluyor). Özellikle endeks seyrek veya tam sayı değilse veya her neyse.

Daha iyi bir yol için önerileriniz var mı?

Teşekkürler!

cevap

20

Pratikte, eşit boyutlu parçaları garanti edemezsiniz: satır sayısı, her şeyden önce, asal olabilir, bu durumda, tek yığın seçenekleriniz, 1 veya büyük bir yığın büyüklüğünde parçalar olabilir. Bir dizi groupby geçiriyorum. başlayarak: Ben kasten 0 olarak ayarlayarak uninformative endeksi yaptık

>>> df = pd.DataFrame(np.random.rand(15, 5), index=[0]*15) 
>>> df[0] = range(15) 
>>> df 
    0   1   2   3   4 
0 0 0.746300 0.346277 0.220362 0.172680 
0 1 0.657324 0.687169 0.384196 0.214118 
0 2 0.016062 0.858784 0.236364 0.963389 
[...] 
0 13 0.510273 0.051608 0.230402 0.756921 
0 14 0.950544 0.576539 0.642602 0.907850 

[15 rows x 5 columns] 

, biz sadece (burada 10) bizim büyüklüğüne karar ve onun tarafından bir dizi tamsayı-bölmek:

>>> df.groupby(np.arange(len(df))//10) 
<pandas.core.groupby.DataFrameGroupBy object at 0xb208492c> 
>>> for k,g in df.groupby(np.arange(len(df))//10): 
...  print(k,g) 
...  
0 0   1   2   3   4 
0 0 0.746300 0.346277 0.220362 0.172680 
0 1 0.657324 0.687169 0.384196 0.214118 
0 2 0.016062 0.858784 0.236364 0.963389 
[...] 
0 8 0.241049 0.246149 0.241935 0.563428 
0 9 0.493819 0.918858 0.193236 0.266257 

[10 rows x 5 columns] 
1  0   1   2   3   4 
0 10 0.037693 0.370789 0.369117 0.401041 
0 11 0.721843 0.862295 0.671733 0.605006 
[...] 
0 14 0.950544 0.576539 0.642602 0.907850 

[5 rows x 5 columns] 

DataFrame'i dilimlemeye dayalı yöntemler, dizin değerleri ile uyumlu olmadığında başarısız olabilir; ancak dizin değerlerini yok saymak ve verilere göre verilere erişmek için her zaman .iloc[a:b] kullanabilirsiniz.

+0

Bu aklımda olan şeydi! Teknik olarak "df.groupby (np.arange (len (df)) // (len (df)/10))" sabit boyut yerine sabit sayıda grup (çekirdek başına 1) elde etmek için. Bazı sebeplerden dolayı, gruplama anahtarının aslında endeksle ilgili olması gerekmediği ortaya çıkmıştı ... –

+1

Verimlilik için orijinal dosyayı bir "yineleyici" kullanarak okumak muhtemelen daha iyi olacaktır. https://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_csv.html) ve bir "chunksize", böylece read_csv işlevi okumayı yapar ve her bir parça, tarafından açıklandığı gibi ayrı bir işleme geçirilebilir. @Ryan –

19

Tam olarak istediğiniz gibi olup olmadığından emin değilim, ancak çok işlevli bir havuz yapmak için oldukça yararlı olan bu gruplayıcı işlevlerini another SO thread'da buldum.

import numpy as np 
import pandas as pds 

df = pds.DataFrame(np.random.rand(14,4), columns=['a', 'b', 'c', 'd']) 

def chunker(seq, size): 
    return (seq[pos:pos + size] for pos in xrange(0, len(seq), size)) 

for i in chunker(df,5): 
    print i 

böyle bir şey verir:

  a   b   c   d 
0 0.860574 0.059326 0.339192 0.786399 
1 0.029196 0.395613 0.524240 0.380265 
2 0.235759 0.164282 0.350042 0.877004 
3 0.545394 0.881960 0.994079 0.721279 
4 0.584504 0.648308 0.655147 0.511390 
      a   b   c   d 
5 0.276160 0.982803 0.451825 0.845363 
6 0.728453 0.246870 0.515770 0.343479 
7 0.971947 0.278430 0.006910 0.888512 
8 0.044888 0.875791 0.842361 0.890675 
9 0.200563 0.246080 0.333202 0.574488 
      a   b   c   d 
10 0.971125 0.106790 0.274001 0.960579 
11 0.722224 0.575325 0.465267 0.258976 
12 0.574039 0.258625 0.469209 0.886768 
13 0.915423 0.713076 0.073338 0.622967 

O yardımcı olur umarım

Burada ne istediğinizi gibi bir şey olabilir iplik, kısa bir örnek. Bu ipython amaçlı dağıtılan kullanarak çok benzer olmalıdır kabul ama sığınak

from multiprocessing import Pool 

nprocs = 4 

pool = Pool(nprocs) 

for chunk in chunker(df, nprocs): 
    data = pool.map(myfunction, chunk) 
    data.domorestuff() 

: Bu durumda

DÜZENLEME

I (yaklaşık) bu şekilde pool of processors Bu işlevi kullanılan Denemedim.

+0

Bu kesinlikle hile yapar. Hala düzgün bir groupby one-liner için tutuyorum, ama bu gibi bir şey gerçekleşmezse, ödülü alırsın :-) –

7

iyi ortamın bir işareti pek çok seçenek olduğunu, bu yüzden bu inşa etti gerçekten Odo

import blaze as bz 
import pandas as pd 

df = pd.DataFrame({'col1':[1,2,3,4,5], 'col2':[2,4,6,8,10]}) 

for chunk in bz.odo(df, target=bz.chunks(pd.DataFrame), chunksize=2): 
    # Do stuff with chunked dataframe 
6

Kullanım numpy kullanarak, Anaconda Blaze bu ekleyeceğiz:() np.array_split

import numpy as np 
import pandas as pd 

data = pd.DataFrame(np.random.rand(10, 3)) 
for chunk in np.array_split(data, 5): 
    assert len(chunk) == len(data)/5 
İlgili konular