2017-02-01 12 views
0

У меня есть вопрос относительно панд и настроенных группировок групп, чтобы найти наиболее эффективный способ расчета моих значений. Вот мой фрагмент кода:Адаптация группы под заказ Pandas

import pandas as pd 

listA = list('abcdefghijklmnopqrstuvwxyz') * 2 
listB = listA[::-1] 
listC = listA[::2] * 2 
listD = "Won" 
data1 = range(52) 
data2 = range(52,104) 
data3 = range(104,156) 

rawStructure = [('A', listA), 
       ('B', listB), 
       ('C', listC), 
       ('D', listD), 
       ('Data1', data1), 
       ('Data2', data2), 
       ('Data3', data3)] 
df = pd.DataFrame.from_items(rawStructure, orient='columns') 

df.loc[40:,"D"] = "Lost" 

def customfct(x,y,z): 
    print('x',x) 
    data = round(((x.sum() + y.sum())/z.sum()) * 100,2) 
    return data 

def f(row): 
    val1 = row.loc[(row['D'] == "Won"), 'Data1'].sum() 
    val2 = row.loc[(row['D'] == "Won"), 'Data2'].sum() 
    val3 = row.loc[(row['D'] == "Won"), 'Data3'].sum() 
    val4 = customfct(row.loc[(row['D'] == "Won"), 'Data1'], row.loc[(row['D'] == "Won"), 'Data2'], row.loc[(row['D'] == "Won"), 'Data3']) 
    return val1, val2, val3, val4 

groupByCriteria = "C" 
agg = df[:].groupby(by=groupByCriteria).apply(f) 
print(agg) 

Я хотел бы знать, если есть более эффективный способ сделать группировку и применять индивидуальные расчеты (например, функции «customfct», в котором используются различные столбцы (Data1, Data2, Data3)). Мой первый подход был похож на то, что вы могли видеть здесь: http://www.shanelynn.ie/summarising-aggregation-and-grouping-data-in-python-pandas/, но представляется невозможным создать формулу, которая не ограничивается одним столбцом (например, lambda x: max (x) - min (x)). Кроме того, как бы вы вернули рамку данных pandas вместо серии pandas (с кортежем)? Заранее спасибо!

Это мой выходной ток (который является правильным, но я предполагаю, что есть более эффективный способ):

Pandas output

+0

Каков ваш первый вопрос? Возможно, фактические данные, текущие результаты, желаемые результаты помогут. – Parfait

+0

Я сделал некоторые изменения в своем оригинальном посте, вам нужно что-нибудь еще? – Sebastian

ответ

0

Рассмотрит агрегирование всех столбцов данных в одном groupby() вызова, а затем создать новый колонка для val4. Затем объедините агрегацию обратно к исходному фрейму.

# EQUIVALENT EXAMPLE DATA 
listA = list('abcdefghijklmnopqrstuvwxyz') * 2 
df = pd.DataFrame({'A': listA, 'B': listA[::-1], 'C': listA[::2] * 2, 
        'D': ["Won" for i in range(40)] + ["Lost" for i in range(40,52)], 
        'Data1': range(52), 'Data2': range(52,104), 'Data3': range(104,156)}) 

# ADJUSTED METHOD 
groupByCriteria = "C" 
grp = df[df['D']=="Won"].groupby(by=groupByCriteria).sum().reset_index()\ 
           .rename(columns={'Data1':'val1','Data2':'val2','Data3':'val3'}) 
grp['val4'] = round(((grp['val1'] + grp['val2'])/grp['val3']) * 100,2) 

agg = df.merge(grp, on='C').sort_values('Data1').reset_index(drop=True) 

В синхронизации сравнения, скорректированный код заметно быстрее. Обратите внимание: ваш метод был скорректирован для возврата кадра данных, а не серии.

def origfct(): 
    def customfct(x,y,z): 
     #print('x',x) 
     data = round(((x.sum() + y.sum())/z.sum()) * 100,2) 
     return data 

    def f(row): 
     row['val1'] = row.loc[(row['D'] == "Won"), 'Data1'].sum() 
     row['val2'] = row.loc[(row['D'] == "Won"), 'Data2'].sum() 
     row['val3'] = row.loc[(row['D'] == "Won"), 'Data3'].sum() 
     row['val4'] = customfct(row.loc[(row['D'] == "Won"), 'Data1'], 
           row.loc[(row['D'] == "Won"), 'Data2'], 
           row.loc[(row['D'] == "Won"), 'Data3']) 
     return row 

    groupByCriteria = "C" 
    agg = df[:].groupby(by=groupByCriteria).apply(f) 
    return agg 

def newsetup(): 
    groupByCriteria = "C" 
    grp = df[df['D']=="Won"].groupby(by=groupByCriteria).sum().reset_index()\ 
          .rename(columns={'Data1':'val1','Data2':'val2','Data3':'val3'}) 
    grp['val4'] = round(((grp['val1'] + grp['val2'])/grp['val3']) * 100,2) 

    agg = df.merge(grp, on='C').sort_values('Data1').reset_index(drop=True) 
    return agg 


python -mtimeit -n'100' -s'import pyscript as test' 'test.origfct()' 
# 100 loops, best of 3: 198 msec per loop 

python -mtimeit -n'100' -s'import pyscript as test' 'test.newsetup()' 
# 100 loops, best of 3: 16 msec per loop 
+0

Это именно то, что я искал. Очень хороший подход для быстрого выполнения этих вычислений. Я не думал о том, чтобы воссоединиться со столами. Большое спасибо! – Sebastian