Yukarıdaki yorumlardan, bunun pandasbir süredir planlandığı anlaşılıyor (ayrıca ilginç görünen bir rosettaproje var az önce fark ettiğim var).
Bununla birlikte, her paralel işlevsellik dahil edilinceye kadar pandas, pandasdoğrudan cython+ OpenMP kullanarak verimli ve bellek kopyalamayan paralel artırmalar yazmanın çok kolay olduğunu fark ettim. ve C ++ .
İşte kullanımı şuna benzer bir paralel grup toplamı yazmaya ilişkin kısa bir örnek:
import pandas as pd
import para_group_demo
df = pd.DataFrame({'a': [1, 2, 1, 2, 1, 1, 0], 'b': range(7)})
print para_group_demo.sum(df.a, df.b)
ve çıktı:
sum
key
0 6
1 11
2 4
Not Şüphesiz, bu basit örneğin işlevselliği eninde sonunda bunun bir parçası olacaktır pandas. Bununla birlikte, bazı şeylerin bir süre C ++ ile paralel hale getirilmesi daha doğal olacaktır ve bunu birleştirmenin ne kadar kolay olduğunun farkında olmak önemlidir pandas.
Bunu yapmak için, kodu takip eden basit bir tek kaynaklı dosya uzantısı yazdım.
Bazı içe aktarmalar ve tür tanımlarıyla başlar
from libc.stdint cimport int64_t, uint64_t
from libcpp.vector cimport vector
from libcpp.unordered_map cimport unordered_map
cimport cython
from cython.operator cimport dereference as deref, preincrement as inc
from cython.parallel import prange
import pandas as pd
ctypedef unordered_map[int64_t, uint64_t] counts_t
ctypedef unordered_map[int64_t, uint64_t].iterator counts_it_t
ctypedef vector[counts_t] counts_vec_t
C ++ unordered_maptürü tek bir iş parçacığı ile toplamak içindir vevector tarafından toplamak içindir ve tüm iş parçacıkları tarafından toplamak içindir.
Şimdi işleve sum. Hızlı erişim için yazılı hafıza görünümleriyle başlar :
def sum(crit, vals):
cdef int64_t[:] crit_view = crit.values
cdef int64_t[:] vals_view = vals.values
İşlev, yarı eşit olarak dişlere bölerek (burada 4'e kodlanmıştır) ve her bir iş parçacığının kendi aralığındaki girişleri toplamıyla devam eder:
cdef uint64_t num_threads = 4
cdef uint64_t l = len(crit)
cdef uint64_t s = l / num_threads + 1
cdef uint64_t i, j, e
cdef counts_vec_t counts
counts = counts_vec_t(num_threads)
counts.resize(num_threads)
with cython.boundscheck(False):
for i in prange(num_threads, nogil=True):
j = i * s
e = j + s
if e > l:
e = l
while j < e:
counts[i][crit_view[j]] += vals_view[j]
inc(j)
İş parçacıkları tamamlandığında, işlev tüm sonuçları (farklı aralıklardan) tek bir sonuçta birleştirir unordered_map:
cdef counts_t total
cdef counts_it_t it, e_it
for i in range(num_threads):
it = counts[i].begin()
e_it = counts[i].end()
while it != e_it:
total[deref(it).first] += deref(it).second
inc(it)
Geriye kalan tek şey bir oluşturmak DataFrameve sonuçları döndürmektir:
key, sum_ = [], []
it = total.begin()
e_it = total.end()
while it != e_it:
key.append(deref(it).first)
sum_.append(deref(it).second)
inc(it)
df = pd.DataFrame({'key': key, 'sum': sum_})
df.set_index('key', inplace=True)
return df