Преобразуйте панды DataFrame с результатами группы - PullRequest
0 голосов
/ 22 мая 2018

Эй, я ищу решение pandas для получения результата из групп DataFrame, а затем применяю эти результаты ко всему кадру данных.Вот минимальный пример того, что я делаю сейчас, но я не нахожу это очень хорошим.

import pandas as np
data = [[0.0, 2.4285714285714286, '0', 'mica02', 'd2o'],
         [10.0, 1.4285714285714286, '225', 'mica02', 'd2o'],
         [13.0, 1.0833333333333333, '225', 'mica02', 'd2o'],
         [954.0, 5.420454545454546, '225', 'mica02', 'air'],
         [937.0, 5.162534435261708, '225', 'mica02', 'air'],
         [75.0, 0.4966887417218543, '225', 'mica02', 'h2o'],
         [78.0, 0.49523809523809526, '225', 'mica02', 'h2o'],
        [80.0, 0.49323809523809526, '225', 'mica01', 'h2o'],
       ]
df0 = pd.DataFrame(data, columns=['basesubed', 'normalized', 'rot', 'm0', 'm1'])
df0

дает, и это сокращенная версия того, с чем я работаю:

    basesubed   normalized  rot     m0  m1
0   0.0     2.428571    0   mica02  d2o
1   10.0    1.428571    225     mica02  d2o
2   13.0    1.083333    225     mica02  d2o
3   954.0   5.420455    225     mica02  air
4   937.0   5.162534    225     mica02  air
5   75.0    0.496689    225     mica02  h2o
6   78.0    0.495238    225     mica02  h2o
7   80.0    0.493238    225     mica01  h2o

Теперь сгруппируйте DataFrame по метаданным m0 и rot и вычислите что-нибудь из группы.Допустим, медиана на данный момент:

mask = (df0.m1 == 'h2o') 
gdf = df0[mask].groupby(['m0', 'rot']).median()
gdf

        basesubed   normalized  basesubed_n     normalized_n
m0  rot                 
mica01  225     80.0    0.493238    1.0     1.0
mica02  225     76.5    0.495963    1.0     1.0

Теперь я хочу вычесть результат из моего исходного DataFrame, но только тогда, когда мультииндекс gdf совпадает с метаданными в df0, поэтому я делаю:

for i in range(len(gdf.index.values)):
    mask = ((df0.m0 == gdf.index.values[i][0]) & (df0.rot == gdf.index.values[i][1]))
    df0.loc[mask, 'basesubed_n'] = df0[mask]['basesubed'] / gdf.loc[gdf.index.values[i]].basesubed
    df0.loc[mask, 'normalized_n'] = df0[mask]['normalized'] / gdf.loc[gdf.index.values[i]].normalized
df0

и я получаю:

    basesubed   normalized  rot     m0  m1  basesubed_n     normalized_n
0   0.0     2.428571    0   mica02  d2o     NaN     NaN
1   10.0    1.428571    225     mica02  d2o     0.130719    2.880397
2   13.0    1.083333    225     mica02  d2o     0.169935    2.184301
3   954.0   5.420455    225     mica02  air     12.470588   10.929142
4   937.0   5.162534    225     mica02  air     12.248366   10.409103
5   75.0    0.496689    225     mica02  h2o     0.980392    1.001462
6   78.0    0.495238    225     mica02  h2o     1.019608    0.998538
7   80.0    0.493238    225     mica01  h2o     1.000000    1.000000

Обратите внимание, как первая строка получила NaN, потому что в gdf не было соответствующей записи.Это именно то, что я хочу, потому что не было rot=0 и m1=h2o в df0.Это несоответствие также является причиной, почему я не смог найти решение, которое использовало df.groupby().transform(), потому что оно также не соответствовало форме фрейма данных, к которому я хотел его применить.

Любая помощь будетбыть приглушенным.

1 Ответ

0 голосов
/ 22 мая 2018

Я не знаю, какой метод transform вы хотите использовать, но вы можете использовать merge, чтобы предотвратить цикл for.Вот идея:

# gdf is slightly different, just reset indexes to merge on them later
gdf = df0[mask].groupby(['m0', 'rot']).median().reset_index()
# merge df0 with gdf on the two columns 'm0', 'rot'
df0 = df0.merge(gdf, on = ['m0',  'rot'], how = 'left', suffixes = ('','_median'))
# now you can calculate the column _n such as:
df0['basesubed_n'] = df0['basesubed'] / df0['basesubed_median']
df0['normalized_n'] = df0['normalized'] / df0['normalized_median']
# finally, drop the columns _median
df0 = df0.drop(['basesubed_median','normalized_median'],1)

И вы получите тот же результат, что и ваш

РЕДАКТИРОВАТЬ: На самом деле, я нашел ответ с transform, просто сделайте:

df0[['basesubed_n','normalized_n']] = df0.groupby(['m0', 'rot'])\
                                         .transform(lambda x: x/x[mask].median())
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...