Повышение скорости, эффективности с помощью панд в векторизованной реализации цикла - PullRequest
0 голосов
/ 25 января 2019

У меня есть (7.5MM, 17) фрейм данных с 500 тыс. Уникальных предметов, которые я «разворачиваю», из-за отсутствия лучшего слова: у каждого уникального предмета может быть N ряд строк, связанных с различными чертами, которыми я являюсь агрегирование в столбцы, так что каждый уникальный элемент имеет только одну строку.

Для этого у меня есть цикл for, повторяющийся над каждым уникальным элементом в кадре данных. Он сортирует фрейм данных во временный фрейм данных, отфильтрованный только по строкам, представленным указанным уникальным элементом. Затем я применяю

df.loc[df['trait']=='xyz'].sum()

для 8 признаков, каждая из которых генерирует агрегированную переменную. Эти переменные затем добавляются во временный список (внутренний цикл), который, в свою очередь, добавляется в выходной список (внешний цикл).

В конце каждого цикла базовый фрейм данных удаляет все строки, связанные с уникальным элементом, так что при увеличении списка вывода размер хранилища базового фрейма данных уменьшается (коэффициент ~ 15).

Я ожидал, что это будет выполняться очень быстро, поскольку, насколько мне известно, манипуляции внутри цикла for являются векторизованной реализацией. Однако через час он прошел только через ~ 7000 строк. Это устанавливает ожидаемое время выполнения всего 3 дня. Я могу с этим смириться, но надеюсь на некоторое понимание более эффективного решения.

Машина, на которой я работаю, имеет 32 ГБ ОЗУ, 5 ТБ памяти. Эта программа занимает всего 5 ГБ ОЗУ. Есть ли способ использовать больше оперативной памяти, но двигаться быстрее?

Любое понимание будет высоко ценится.

редактировать -

wolst = []
cnt = 0

for i in wodf['WON'].unique().tolist():
    tlst = []
    wo = i

    tdf = wodf.loc[wodf['WON']==i]

    matsum = tdf.loc[tdf['LIT']=="M",'LIC'].sum()
    labsum = tdf.loc[tdf['LIT']=="L", 'LIC'].sum()
    labhrs = tdf.loc[tdf['LIT']=="L", 'Q'].sum()
    tcsum = tdf.loc[tdf['LIT']=="T", 'LIC'].sum()
    numtrp = tdf.loc[tdf['LIT']=="T", 'Q'].sum()
    pmusum = tdf.loc[tdf['LIT']=="PM", 'LIC'].sum()
    prtsum = tdf.loc[tdf['LIT']=="P", 'LIC'].sum()
    stdsum = tdf.loc[tdf['LIT']=="S", 'LIC'].sum()
    stdhrs = tdf.loc[tdf['LIT']=="S", 'Q'].sum()

    labsum = labsum+stdsum
    labhrs = labhrs+stdhrs

    if labsum is None:
        labsum = 0
    if labhrs is None:
        labhrs = 0
    if matsum is None:
        matsum=0
    if tcsum is None:
        tcsum=0
    if numtrp is None:
        numtrp=0
    if pmusum is None:
        pmusum=0
    if prtsum is None:
        prtsum=0

    tlst.append([wo,labsum,labhrs,matsum,tcsum,numtrp,pmusum,prtsum])
    wolst.append(tlst)

    print(cnt)
    cnt+=1

Где wodf (7,5 мм, 17)

1 Ответ

0 голосов
/ 25 января 2019

Вы группируете по "WON" и "LIT" и суммируете "LIC" и "Q"?

Вот пример того, как groupby может сделать нечто подобное.

In [42]: df = pd.DataFrame({'WON' : ['foo', 'bar', 'foo', 'bar', 
    ...:    ...:                           'foo', 'bar', 'foo', 'foo'], 
    ...:    ...:                    'LIT' : ['one', 'one', 'two', 'three', 
    ...:    ...:                           'two', 'two', 'one', 'three'], 
    ...:    ...:                    'LIC' : np.random.randn(8), 
    ...:    ...:                    'Q' : np.random.randn(8)})                             

In [43]: df                                                                                
Out[43]: 
   WON    LIT       LIC         Q
0  foo    one  0.148776  1.963984
1  bar    one  0.008530 -0.494986
2  foo    two  0.218419  0.384919
3  bar  three  0.944845 -0.185242
4  foo    two  0.218473  1.505220
5  bar    two  0.669328  0.146424
6  foo    one -0.861758  0.482464
7  foo  three -0.627680  1.604041

In [44]: df.groupby(['WON', 'LIT'])['LIC', 'Q'].sum().unstack()                            
Out[44]: 
          LIC                             Q                    
LIT       one     three       two       one     three       two
WON                                                            
bar  0.008530  0.944845  0.669328 -0.494986 -0.185242  0.146424
foo -0.712981 -0.627680  0.436891  2.446449  1.604041  1.890139

In [45]: df.groupby(['WON', 'LIT'])['LIC', 'Q'].sum()                                      
Out[45]: 
                LIC         Q
WON LIT                      
bar one    0.008530 -0.494986
    three  0.944845 -0.185242
    two    0.669328  0.146424
foo one   -0.712981  2.446449
    three -0.627680  1.604041
    two    0.436891  1.890139

Если использование ОЗУ является проблемой, вы можете взглянуть на проект dask , который может обрабатывать нехватку памяти с помощью API-интерфейса, подобного pandas

Я бы указал на:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...