Расчеты с использованием Pandas apply и лямбда - PullRequest
0 голосов
/ 13 июля 2020

У меня есть фрейм данных со столбцом для дат (формат YYYY / MM / DD) и столбец для измерений скорости ветра. С каждой датой связано более одного измерения скорости ветра, и я хочу вычислить стандартную ошибку измерения скорости ветра на каждый день.

Я использую pandas 'groupby' для группировки всего ветра скорости до даты, на которую они были сняты, и я вычисляю среднее значение и количество измерений, сделанных за каждый день.

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

Есть ли лучший способ go об этом?

#calculate daily averages, daily number of measurements, and list of every value from day
average_from_date = df.groupby(['time'])['wind_spd_ms'].mean()
number = df.groupby(['time'])['wind_spd_ms'].count()
values_from_date = df.groupby(['time'])['wind_spd_ms'].apply(list)

#return list of standard errors for each date in the data set
standard_errors = df.groupby(['time'])['wind_spd_ms'].apply(lambda x: (sum((values_from_date - 
average_from_date)**2)/(number-1)))

Ответы [ 2 ]

2 голосов
/ 13 июля 2020

Хотя groupby.GroupBy.sem - хороший способ вычислить это, поскольку это готовая функция в pandas, могут быть случаи, когда вам нужно вычислить новый столбец с функцией, которая не существует в библиотеке.

apply () + lambda

Вот как вы бы вычислили новый столбец * с помощью подхода «применить lambda»:

res1 = df.groupby(['time'])['wind_spd_ms'].apply(lambda x: ((x-np.mean(x))**2)/(len(x)-1))

Что важно понимать, поскольку df.groupby(['time']) - это объект DataFrame (GroupBy), df.groupby(['time'])['wind_spd_ms'] - это объект Series (GroupBy), а функция apply(), следовательно, - pd.Series.apply . Он принимает функцию в качестве аргумента, и функция будет вызываться с серией pandas (здесь: df.groupby(['time'])['wind_spd_ms']) в качестве аргумента. Теперь вы уже знаете, как рассчитать стандартное отклонение, если вы получили список / серию.

apply () + другая функция

С помощью apply вы не ограничены лямбдами, но аргумент может быть любой функцией, которая принимает pd.Series в качестве аргумента. Таким образом, не менее хорошим решением было бы.

def calculate_std(x):
    ave = np.mean(x)
    return ((x-ave)**2)/(len(x)-1)

res2 = df.groupby(['time'])['wind_spd_ms'].apply(calculate_std)

С немного более сложными вычислениями это гораздо более читаемое и предпочтительное решение .

Насколько быстро работают разные альтернативы?

Можно подумать, что «использование лямбда-выражений быстрее», но если вы сами рассчитаете время функций, то увидите, что прирост скорости от использования лямбда-выражений не происходит:

In [3]: timeit df.groupby(['time'])['wind_spd_ms'].apply(lambda x: ((x-np.mean(x))**2)/(len(x)-1))
3.26 ms ± 358 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [4]: timeit df.groupby(['time'])['wind_spd_ms'].apply(calculate_std)
2.87 ms ± 63.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

С другой стороны, функция sem, упомянутая oli5679 , работает быстрее

In [5]: timeit df.groupby(['time'])['wind_spd_ms'].sem()
1.33 ms ± 40.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

(хотя функции библиотеки не всегда самые быстрые. Например, использование scipy.ndimage.interpolation.shift для смещения .. )


* Это уравнение для группового стандартного отклонения (не стандартная ошибка группового среднего)

1 голос
/ 13 июля 2020

Pandas groupby имеет «sem», который можно использовать без создания собственной лямбда-функции. См. Дополнительную информацию здесь .

import pandas as pd

test = pd.DataFrame({'group':['a','a','a','b','b','b'],'val':[1,100,-40,5,7,8]})

test.groupby(['group'])['val'].sem()
#a    41.554516
#b     0.881917

См. Ниже пример того, как сделать это с нуля. Я думаю, что первоначальная попытка не совсем подходила определению здесь . Вы должны разделить общую квадратную разницу от среднего на N-1, чтобы вычислить дисперсию выборки, но также необходимо разделить это на N и возвести в квадрат root, чтобы получить SEM.

test["squared_difference_from_average"] = (
    test["val"] - test.groupby(["group"])["val"].transform("mean")
) ** 2

group_count = test.groupby(["group"])["val"].count()

standard_errors = (
    (
        (test.groupby(["group"]) ["squared_difference_from_average"].sum())
        / (group_count - 1)
    )
    / group_count
) ** 0.5
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...