Применение функции средневзвешенного значения к столбцу в объекте pandas groupby с переносом весов для расчета неопределенностей - PullRequest
0 голосов
/ 16 апреля 2020

Я попытался расширить этот вопрос, чтобы обобщить его на случай, когда кто-то хочет перенести сумму весов в средневзвешенное значение, чтобы можно было добавить к результирующим данным кадры неопределенностей на средневзвешенных значениях, которые 1 / (sqrt(sum_of_weights))

Рассмотрим примерный кадр данных

import pandas as pd
import numpy as np
df5 = pd.DataFrame.from_dict({'Lab': ['Lab1','Lab1','Lab1','Lab2','Lab2','Lab2','Lab3','Lab3','Lab3'],
                'test_type': ['a','a','b','b','c','c','a','a','a'],
                'HVL' : [1.4,1.4,1.4,1.3,1.3,1.3,1.35,1.35,1.35],
                'measurements': [2.1,2.0,2.5,1.7,1.7,1.9,2.8,2.8,2.7], 
                'unc': [0.4,0.4,0.1,0.2,0.3,0.3,0.15,0.15,0.15]},
                ) 

, суммирующий измерения нескольких Labs по трем различным test_types, на которых Lab ' Методы измерения имеют различную точность, отраженную в различных значениях в их заявленных неопределенностях unc. Давайте рассмотрим следующую функцию для вычисления взвешенного среднего и переноса весов для оценки неопределенностей:

def wgt_average(x):
    '''
    wgt_average: calculates the weighted average on a particular column 
    of a groupby object. To be applied to the groupby object via .apply(wgt_average)
    Parameters
    ----------
    x : the groupby object

    Returns
    -------
    dataframe
        averages: the weighted averages
        unc : their uncertainties obtained from the square root of the sum of the 
            weights

    '''
    if (x['unc'] > 0).all() & (x['measurements'] > 0).all():
        weights = 1 / (x['unc'])**2
        avg = np.average(x['measurements'],
                         weights=weights,
                         axis=0,
                         returned = True) # will return a tuple that needs further work
        df = pd.DataFrame.from_records(np.vstack(avg).T, 
                                       columns=['averages','weights_sum'])
        uncertainties = 1/np.sqrt(df['weights_sum'])

        df = pd.concat([df.drop(columns=['weights_sum']), uncertainties], 
                       axis=1)
        df.columns = ['averages', 'unc']
        return df
    else:
        return 0

. Может применяться как

df5_ave = (df5.groupby(['test_type']).apply(wgt_average))

, но это приводит к многоиндексированному кадру данных.

             averages       unc
test_type                      
a         0  2.705238  0.082808
b         0  2.340000  0.089443
c         0  1.800000  0.212132

, который можно устранить, опустив последний уровень индекса (будет улучшено)

df5_ave.index = df5_ave.index.droplevel(-1)

Это также работает для немного более продвинутых объектов groupby:

df5_ave = (df5.groupby(['test_type', 'HVL']).apply(wgt_average))
df5_ave.index = df5_ave.index.droplevel(-1)
print(df5_ave)
                averages       unc
test_type HVL                     
a         1.35  2.766667  0.086603
          1.40  2.050000  0.282843
b         1.30  1.700000  0.200000
          1.40  2.500000  0.100000
c         1.30  1.800000  0.212132

Проблемы, возникающие с образцом набора данных Seaborn

Однако в этом подходе должно быть что-то не так, как будто я пытаюсь применить его к другим фреймам данных, и получаю ошибки. Загрузка набора данных seaborn planets, например:

import numpy as np
import pandas as pd
import seaborn as sns

planets = sns.load_dataset('planets')
# planets.groupby(by=['year', 'method']).mean()

def wgt_average(x):
    '''
    wgt_average: calculates the weighted average on a particular column 
    of a groupby object. To be applied to the groupby object via .apply(wgt_average)
    Parameters
    ----------
    x : the groupby object

    Returns
    -------
    dataframe
        averages: the weighted averages
        unc : their uncertainties obtained from the square root of the sum of the 
            weights

    '''
    if (x['mass'] > 0).all() & (x['orbital_period'] > 0).all():
        weights = 1 / (x['mass'])**2
        avg = np.average(x['orbital_period'],
                         weights=weights,
                         axis=0,
                         returned = True) # will return a tuple that needs further work
        df = pd.DataFrame.from_records(np.vstack(avg).T, 
                                       columns=['averages','weights_sum'])
        uncertainties = 1/np.sqrt(df['weights_sum'])

        df = pd.concat([df.drop(columns=['weights_sum']), uncertainties], 
                       axis=1)
        df.columns = ['averages', 'unc']
        return df
    else:
        return 0

orbitals_avg = (planets.groupby(by=['year', 'method'])).apply(wgt_average)

, приводит к:

File "/anaconda3/lib/python3.7/site-packages/ pandas / core / groupby / groupby.py ", строка 958, в reset_identity ax = v._get_axis (self.axis)

AttributeError: у объекта int нет атрибута _get_axis

Это связано с тем, как я определил метод среднего взвешивания?

...