Изучение кратких путей в pandas для GROUPBY & JOIN без создания промежуточных фреймов данных - PullRequest
0 голосов
/ 15 февраля 2020

Пытаясь сократить свой код, я заметил, что мне часто приходится группировать, а затем присоединять сгруппированный фрейм данных к родительскому. Есть ли способы написать более элегантный и лаконичный код? Пожалуйста, проверьте мой пример ниже:

Предположим, что этот родительский фрейм данных: (вы можете копировать и вставлять для воспроизведения)

chem_1=np.array([-5, 9, -1,4,-2,3,4,np.nan,np.nan,np.nan,8,np.nan,9])
chem_2=np.array([6, -1, -4,np.nan,-7,-5,5,np.nan,10,-9,8,6,np.nan])
frame_total=pd.DataFrame(list(zip(chem_1,chem_2)), columns=['chem_1', 'chem_2'])
frame_total['sum_hourly']=frame_total.sum(axis=1)
frame_total.loc[frame_total[['chem_1', 'chem_2']].isnull().all(1),'sum_hourly']=np.nan
frame_total.index=pd.date_range('2018-01-01', periods=13, freq='6H')
print(frame_total)

                     chem_1  chem_2  sum_hourly
2018-01-01 00:00:00    -5.0     6.0         1.0
2018-01-01 06:00:00     9.0    -1.0         8.0
2018-01-01 12:00:00    -1.0    -4.0        -5.0
2018-01-01 18:00:00     4.0     NaN         4.0
2018-01-02 00:00:00    -2.0    -7.0        -9.0
2018-01-02 06:00:00     3.0    -5.0        -2.0
2018-01-02 12:00:00     4.0     5.0         9.0
2018-01-02 18:00:00     NaN     NaN         NaN
2018-01-03 00:00:00     NaN    10.0        10.0
2018-01-03 06:00:00     NaN    -9.0        -9.0
2018-01-03 12:00:00     8.0     8.0        16.0
2018-01-03 18:00:00     NaN     6.0         6.0
2018-01-04 00:00:00     9.0     NaN         9.0

ПРИМЕР: Ниже описаны простые groupby и join, которые заполнят столбец sum_24_a, в котором суммируются значения часовых сумм за календарный день. Однако недавно я обнаружил, что могу сократить это, применив вторую часть кода, которая заполняет столбец «sum_24_b»

# first part: create a dataframe and then join to get column 'sum_24_a'
frame_sum=frame_total.groupby(frame_total.index.date)['sum_hourly'].sum().to_frame('sum_24_a')
frame_total=frame_total.join(frame_sum)

# second part: directly create column 'sum_24_b' without the need of joining
frame_total['sum_24_b']=frame_total['sum_hourly'].groupby(frame_total.index.date).sum()

print(frame_total)

                     chem_1  chem_2  sum_hourly  sum_24_a  sum_24_b
2018-01-01 00:00:00    -5.0     6.0         1.0       8.0       8.0
2018-01-01 06:00:00     9.0    -1.0         8.0       NaN       NaN
2018-01-01 12:00:00    -1.0    -4.0        -5.0       NaN       NaN
2018-01-01 18:00:00     4.0     NaN         4.0       NaN       NaN
2018-01-02 00:00:00    -2.0    -7.0        -9.0      -2.0      -2.0
2018-01-02 06:00:00     3.0    -5.0        -2.0       NaN       NaN
2018-01-02 12:00:00     4.0     5.0         9.0       NaN       NaN
2018-01-02 18:00:00     NaN     NaN         NaN       NaN       NaN
2018-01-03 00:00:00     NaN    10.0        10.0      23.0      23.0
2018-01-03 06:00:00     NaN    -9.0        -9.0       NaN       NaN
2018-01-03 12:00:00     8.0     8.0        16.0       NaN       NaN
2018-01-03 18:00:00     NaN     6.0         6.0       NaN       NaN
2018-01-04 00:00:00     9.0     NaN         9.0       9.0       9.0

ВОПРОС: Есть ли подобное предложение для выполнения после более сложных GROUPBY, AGG и JOIN без необходимости создавать фрейм данных frame_day и затем присоединять его к оригиналу, как показано ниже?

frame_day=frame_total.between_time('10:00:00', '16:00:00').\
          groupby(frame_total.between_time('10:00:00', '16:00:00').index.date)['sum_hourly'].\
          agg([('sum_day', lambda x: x.sum()), \
               ('positive_sum_day', lambda x: x[x>0].sum()), \
               ('negative_sum_day', lambda x: x[x<0].sum())])
frame_total=frame_total.join(frame_day)

print(frame_total.head(8))

                     chem_1  chem_2  sum_hourly  sum_24_a  sum_24_b  \
2018-01-01 00:00:00    -5.0     6.0         1.0       8.0       8.0   
2018-01-01 06:00:00     9.0    -1.0         8.0       NaN       NaN   
2018-01-01 12:00:00    -1.0    -4.0        -5.0       NaN       NaN   
2018-01-01 18:00:00     4.0     NaN         4.0       NaN       NaN   
2018-01-02 00:00:00    -2.0    -7.0        -9.0      -2.0      -2.0   
2018-01-02 06:00:00     3.0    -5.0        -2.0       NaN       NaN   
2018-01-02 12:00:00     4.0     5.0         9.0       NaN       NaN   
2018-01-02 18:00:00     NaN     NaN         NaN       NaN       NaN   

                     sum_day  positive_sum_day  negative_sum_day  
2018-01-01 00:00:00     -5.0               0.0              -5.0  
2018-01-01 06:00:00      NaN               NaN               NaN  
2018-01-01 12:00:00      NaN               NaN               NaN  
2018-01-01 18:00:00      NaN               NaN               NaN  
2018-01-02 00:00:00      9.0               9.0               0.0  
2018-01-02 06:00:00      NaN               NaN               NaN  
2018-01-02 12:00:00      NaN               NaN               NaN  
2018-01-02 18:00:00      NaN               NaN               NaN  

Надеюсь, мой вопрос и пример понятны. Заранее спасибо!

1 Ответ

0 голосов
/ 15 февраля 2020

Что касается первого вопроса, вот решение. Вы можете опустить столбец даты позже, если он вам не нужен.

frame_total['date'] = frame_total.index.date
frame_total['sum_24_a'] = frame_total.groupby('date')['sum_hourly'].sum()
print(frame_total)

                     chem_1  chem_2  sum_hourly        date  sum_24_a
2018-01-01 00:00:00    -5.0     6.0         1.0  2018-01-01       8.0
2018-01-01 06:00:00     9.0    -1.0         8.0  2018-01-01       NaN
2018-01-01 12:00:00    -1.0    -4.0        -5.0  2018-01-01       NaN
2018-01-01 18:00:00     4.0     NaN         4.0  2018-01-01       NaN
2018-01-02 00:00:00    -2.0    -7.0        -9.0  2018-01-02      -2.0
2018-01-02 06:00:00     3.0    -5.0        -2.0  2018-01-02       NaN
2018-01-02 12:00:00     4.0     5.0         9.0  2018-01-02       NaN
2018-01-02 18:00:00     NaN     NaN         NaN  2018-01-02       NaN
2018-01-03 00:00:00     NaN    10.0        10.0  2018-01-03      23.0
2018-01-03 06:00:00     NaN    -9.0        -9.0  2018-01-03       NaN
2018-01-03 12:00:00     8.0     8.0        16.0  2018-01-03       NaN
2018-01-03 18:00:00     NaN     6.0         6.0  2018-01-03       NaN
2018-01-04 00:00:00     9.0     NaN         9.0  2018-01-04       9.0

Что касается второго вопроса, вот простой способ создать столбец sum_day. Другие могут быть построены таким же образом:

frame_total['sum_day'] = frame_total.loc[
    frame_total.between_time('10:00:00', '16:00:00').index] \
    .groupby('date')['sum_hourly'].agg('sum')
print(frame_total.head(8))

                     chem_1  chem_2  sum_hourly        date  sum_24_a  sum_day
2018-01-01 00:00:00    -5.0     6.0         1.0  2018-01-01       8.0     -5.0
2018-01-01 06:00:00     9.0    -1.0         8.0  2018-01-01       NaN      NaN
2018-01-01 12:00:00    -1.0    -4.0        -5.0  2018-01-01       NaN      NaN
2018-01-01 18:00:00     4.0     NaN         4.0  2018-01-01       NaN      NaN
2018-01-02 00:00:00    -2.0    -7.0        -9.0  2018-01-02      -2.0      9.0
2018-01-02 06:00:00     3.0    -5.0        -2.0  2018-01-02       NaN      NaN
2018-01-02 12:00:00     4.0     5.0         9.0  2018-01-02       NaN      NaN
2018-01-02 18:00:00     NaN     NaN         NaN  2018-01-02       NaN      NaN
...