У меня около 7 миллионов строк в HDFStore
с более чем 60 столбцами. Данные больше, чем я могу вписаться в память. Я ищу для объединения данных в группы на основе значения столбца "А". Документация для pandas split/aggregating/combination предполагает, что у меня есть все мои данные в DataFrame
, но я не могу прочитать весь магазин в в памяти DataFrame
. Каков правильный подход для группировки данных в HDFStore
?
Pandas "Группировка по" Запрос больших данных в HDFStore?
Ответ 1
Вот полный пример.
import numpy as np
import pandas as pd
import os
fname = 'groupby.h5'
# create a frame
df = pd.DataFrame({'A': ['foo', 'foo', 'foo', 'foo',
'bar', 'bar', 'bar', 'bar',
'foo', 'foo', 'foo'],
'B': ['one', 'one', 'one', 'two',
'one', 'one', 'one', 'two',
'two', 'two', 'one'],
'C': ['dull', 'dull', 'shiny', 'dull',
'dull', 'shiny', 'shiny', 'dull',
'shiny', 'shiny', 'shiny'],
'D': np.random.randn(11),
'E': np.random.randn(11),
'F': np.random.randn(11)})
# create the store and append, using data_columns where I possibily
# could aggregate
with pd.get_store(fname) as store:
store.append('df',df,data_columns=['A','B','C'])
print "store:\n%s" % store
print "\ndf:\n%s" % store['df']
# get the groups
groups = store.select_column('df','A').unique()
print "\ngroups:%s" % groups
# iterate over the groups and apply my operations
l = []
for g in groups:
grp = store.select('df',where = [ 'A=%s' % g ])
# this is a regular frame, aggregate however you would like
l.append(grp[['D','E','F']].sum())
print "\nresult:\n%s" % pd.concat(l, keys = groups)
os.remove(fname)
Выход
store:
<class 'pandas.io.pytables.HDFStore'>
File path: groupby.h5
/df frame_table (typ->appendable,nrows->11,ncols->6,indexers->[index],dc->[A,B,C])
df:
A B C D E F
0 foo one dull -0.815212 -1.195488 -1.346980
1 foo one dull -1.111686 -1.814385 -0.974327
2 foo one shiny -1.069152 -1.926265 0.360318
3 foo two dull -0.472180 0.698369 -1.007010
4 bar one dull 1.329867 0.709621 1.877898
5 bar one shiny -0.962906 0.489594 -0.663068
6 bar one shiny -0.657922 -0.377705 0.065790
7 bar two dull -0.172245 1.694245 1.374189
8 foo two shiny -0.780877 -2.334895 -2.747404
9 foo two shiny -0.257413 0.577804 -0.159316
10 foo one shiny 0.737597 1.979373 -0.236070
groups:Index([bar, foo], dtype=object)
result:
bar D -0.463206
E 2.515754
F 2.654810
foo D -3.768923
E -4.015488
F -6.110789
dtype: float64
Некоторые оговорки:
1) Эта методология имеет смысл, если плотность вашей группы относительно низкая. Порядка сотен или тысяч групп. Если вы получаете больше, чем более эффективные (но более сложные методы), и ваша функция, которую вы применяете (в данном случае sum
), становится более ограничительной.
По существу, вы бы итератор по всему магазину кусками, группируя по ходу дела, но сохраняя группы только полуразрушенными (представьте, что вы делаете среднее значение, так что вам нужно будет сохранить текущую сумму плюс текущее количество, а затем разделить на конец). Таким образом, некоторые операции будут немного сложнее, но могут потенциально обрабатывать МНОГИЕ группы (и очень быстро).
2) эффективность этого можно было бы улучшить, сохранив координаты (например, расположение групп, но это немного сложнее)
3) с этой схемой невозможна многогрупповая (это возможно, но требует более приближенного подхода 2) выше
4) столбцы, которые вы хотите сгруппировать, ДОЛЖНЫ быть data_column!
5) вы можете комбинировать любой другой фильтр, который вы хотите выбрать в выборе btw (который является неприхотливым способом многопользовательской битвы, вы просто формируете 2 уникальных списка группы и итератора над их продуктом, а не очень эффективно, если у вас много групп, но они могут работать)
НТН
сообщите мне, если это сработает для вас