Передискретизация Pandas кадра данных без заполнения пропущенного времени - PullRequest
1 голос
/ 09 июля 2020

Повторная выборка фрейма данных может привести фрейм данных к более высокому или более низкому временному разрешению. В большинстве случаев это используется для go для снижения разрешения (например, пересчет 1-минутных данных на ежемесячные значения). Когда набор данных является разреженным (например, данные не собирались в феврале 2020 г.), тогда строка февраля 2020 г. будет заполнена NaN в повторно выбранном кадре данных. Проблема заключается в том, что запись данных длинная И разреженная, имеется много строк NaN, что делает фрейм данных излишне большим и занимает много времени ЦП. Например, рассмотрим этот фрейм данных и операцию повторной выборки:

import numpy as np
import pandas as pd

freq1 = pd.date_range("20000101", periods=10, freq="S")
freq2 = pd.date_range("20200101", periods=10, freq="S")

index = np.hstack([freq1.values, freq2.values])
data = np.random.randint(0, 100, (20, 10))
cols = list("ABCDEFGHIJ")

df = pd.DataFrame(index=index, data=data, columns=cols)

# now resample to daily average
df = df.resample(rule="1D").mean()

Большая часть данных в этом фрейме данных бесполезна и может быть удалена с помощью:

df.dropna(how="all", axis=0, inplace=True)

, однако это небрежно. Есть ли другой метод для повторной выборки фрейма данных, который не заполняет все пробелы данных с помощью NaN (т.е. в приведенном выше примере результирующий фрейм данных будет иметь только две строки)?

1 Ответ

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

Здесь вы можете использовать groupby вместо resample:

df = df.groupby(df.index.date).mean()

Это хорошо работает для правила "1D", потому что вы можете легко найти уникальные даты в наборе данных. Сроки, это быстрее, чем повторная выборка:

%%timeit
df.resample(rule='1D').mean().dropna(how="all", axis=0, inplace=True)
#2.79 ms ± 77.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%%timeit
df.groupby(df.index.date).mean()
#974 µs ± 10.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Я также подумал о проверке каждой передискретизированной корзины, чтобы увидеть, пуста ли она перед присоединением, но это паршиво :

%%timeit
pd.DataFrame([d.mean(axis=0).rename(i) for i,d in df.resample(rule="1D") if not d.empty])
#899 ms ± 19.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Я могу представить, что версия groupby будет более сложной с разными частотами, или скажем, если вы хотите усреднить несколько единиц времени вместо одной (скажем, выполняя здесь "4D", возможно, если бы у вас были данные за 2 недели по каждый конец). Но, возможно, это все еще будет возможно либо путем переименования некоторых дат, либо путем использования нескольких атрибутов времени в вызове groupby.

Я также думал о попытке использовать pd.cut, но это также значительно хуже (я включите строительную строку df, чтобы %%timeit работал, но результаты для resample по сути такие же, если он также включен туда):

%%timeit
df = pd.DataFrame(index=index, data=data, columns=cols)
dr = pd.date_range(df.index.min(), df.index.max() + pd.Timedelta(days=1), freq='1D') #resample at the desired frequency and add an extra bin to make sure all data is inlcuded
bins = pd.cut(df.index, dr, include_lowest=True, right=False)
df.index = bins.remove_unused_categories()
output = df.groupby(df.index).mean()
#101 ms ± 832 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...