Я работаю с интервальными данными коммунального счетчика, которые состоят из метки времени (обычно с шагом 1 час или 15 минут) и значения потребления энергии (в кВт или кВтч). Я хотел бы быстро преобразовать фрейм данных pandas с отдельными показаниями в годовую сводку со средними значениями, максимальными значениями и подсчетами в месяц, в час.
Формат годовой сводки будет представлять собой таблицу за 12 месяцев x 24 часа (288 отдельных ячеек), где каждая ячейка представляет собой либо среднее, либо максимальное значение, либо количество всех значений за этот конкретный месяц и час.
Для простоты давайте просто посмотрим на подсчет количества. (Из предложений я могу сделать вывод о выполнении аналогичных вычислений для средних и максимальных значений.)
Я попробовал грубый подход к фильтрации временных меток по месяцам и часам (цикл из 288 значений) и сведению подсчетов в матрицу. Однако этот подход кажется очень медленным, поскольку я выполняю эти расчеты даже на 20 метрах. Мне любопытно, есть ли более быстрый способ добиться этого с использованием pandas/numpy.
Ниже приведен пример форматирования интервальных данных.
from datetime import datetime
import pandas as pd
df = pd.DataFrame()
df["start"] = pd.date_range(start=datetime(2018, 1, 1), end=datetime(2018, 12, 31, 23), freq='900S')
df["value"] = 1
df.set_index("start", inplace=True)
В настоящее время я выполняю расчет по следующим направлениям:
for month in range(1, 13):
for hour in range(0, 24):
count = df.query("index.dt.month == {} and index.dt.hour == {}".format(month, hour)).count()
Вывод счетчиков для этих данных будет выглядеть следующим образом. (Примечание: иногда данные не полные, что может помочь определить эта таблица.)
1 2 3 4 5 6 7 8 9 10 11 12
0 124 112 124 120 124 120 124 124 120 124 120 124
1 124 112 124 120 124 120 124 124 120 124 120 124
2 124 112 124 120 124 120 124 124 120 124 120 124
3 124 112 124 120 124 120 124 124 120 124 120 124
4 124 112 124 120 124 120 124 124 120 124 120 124
5 124 112 124 120 124 120 124 124 120 124 120 124
6 124 112 124 120 124 120 124 124 120 124 120 124
7 124 112 124 120 124 120 124 124 120 124 120 124
8 124 112 124 120 124 120 124 124 120 124 120 124
9 124 112 124 120 124 120 124 124 120 124 120 124
10 124 112 124 120 124 120 124 124 120 124 120 124
11 124 112 124 120 124 120 124 124 120 124 120 124
12 124 112 124 120 124 120 124 124 120 124 120 124
13 124 112 124 120 124 120 124 124 120 124 120 124
14 124 112 124 120 124 120 124 124 120 124 120 124
15 124 112 124 120 124 120 124 124 120 124 120 124
16 124 112 124 120 124 120 124 124 120 124 120 124
17 124 112 124 120 124 120 124 124 120 124 120 124
18 124 112 124 120 124 120 124 124 120 124 120 124
19 124 112 124 120 124 120 124 124 120 124 120 124
20 124 112 124 120 124 120 124 124 120 124 120 124
21 124 112 124 120 124 120 124 124 120 124 120 124
22 124 112 124 120 124 120 124 124 120 124 120 124
23 124 112 124 120 124 120 124 124 120 124 120 124
Вы можете использовать pandas.crosstab
, а затем, при необходимости, использовать DataFrame.rename_axis
для удаления имен осей в соответствии с желаемым результатом.
df_new = (pd.crosstab(df.index.hour, df.index.month)
.rename_axis(None)
.rename_axis(None, axis=1))
[выход]
1 2 3 4 5 6 7 8 9 10 11 12
0 124 112 124 120 124 120 124 124 120 124 120 124
1 124 112 124 120 124 120 124 124 120 124 120 124
2 124 112 124 120 124 120 124 124 120 124 120 124
3 124 112 124 120 124 120 124 124 120 124 120 124
4 124 112 124 120 124 120 124 124 120 124 120 124
5 124 112 124 120 124 120 124 124 120 124 120 124
6 124 112 124 120 124 120 124 124 120 124 120 124
7 124 112 124 120 124 120 124 124 120 124 120 124
8 124 112 124 120 124 120 124 124 120 124 120 124
9 124 112 124 120 124 120 124 124 120 124 120 124
10 124 112 124 120 124 120 124 124 120 124 120 124
11 124 112 124 120 124 120 124 124 120 124 120 124
12 124 112 124 120 124 120 124 124 120 124 120 124
13 124 112 124 120 124 120 124 124 120 124 120 124
14 124 112 124 120 124 120 124 124 120 124 120 124
15 124 112 124 120 124 120 124 124 120 124 120 124
16 124 112 124 120 124 120 124 124 120 124 120 124
17 124 112 124 120 124 120 124 124 120 124 120 124
18 124 112 124 120 124 120 124 124 120 124 120 124
19 124 112 124 120 124 120 124 124 120 124 120 124
20 124 112 124 120 124 120 124 124 120 124 120 124
21 124 112 124 120 124 120 124 124 120 124 120 124
22 124 112 124 120 124 120 124 124 120 124 120 124
23 124 112 124 120 124 120 124 124 120 124 120 124
@AndyHayden да точно
"вычисляет таблицу частот факторов, если не передан массив значений и функция агрегирования" ах, хорошо.
Работает как шарм! Просто для справки: я смог вычислить «среднее» и «максимальное» с помощью pd.crosstab(df.index.hour, df.index.month, df.values, aggfunc=aggfunc)
, где aggfunc
— это np.mean
и np.max
соответственно.
Я бы использовал groupby, а затем распаковал:
In [11]: res = df.groupby([df.index.month, df.index.hour])["value"].sum().unstack(0, fill_value=0)
In [12]: res.columns.name = "month" # or None to suppress
In [13]: res.index.name = "hour" # or None to suppress
In [14]: res
Out[44]:
month 1 2 3 4 5 6 7 8 9 10 11 12
hour
0 124 112 124 120 124 120 124 124 120 124 120 124
1 124 112 124 120 124 120 124 124 120 124 120 124
2 124 112 124 120 124 120 124 124 120 124 120 124
3 124 112 124 120 124 120 124 124 120 124 120 124
4 124 112 124 120 124 120 124 124 120 124 120 124
5 124 112 124 120 124 120 124 124 120 124 120 124
6 124 112 124 120 124 120 124 124 120 124 120 124
7 124 112 124 120 124 120 124 124 120 124 120 124
8 124 112 124 120 124 120 124 124 120 124 120 124
9 124 112 124 120 124 120 124 124 120 124 120 124
10 124 112 124 120 124 120 124 124 120 124 120 124
11 124 112 124 120 124 120 124 124 120 124 120 124
12 124 112 124 120 124 120 124 124 120 124 120 124
13 124 112 124 120 124 120 124 124 120 124 120 124
14 124 112 124 120 124 120 124 124 120 124 120 124
15 124 112 124 120 124 120 124 124 120 124 120 124
16 124 112 124 120 124 120 124 124 120 124 120 124
17 124 112 124 120 124 120 124 124 120 124 120 124
18 124 112 124 120 124 120 124 124 120 124 120 124
19 124 112 124 120 124 120 124 124 120 124 120 124
20 124 112 124 120 124 120 124 124 120 124 120 124
21 124 112 124 120 124 120 124 124 120 124 120 124
22 124 112 124 120 124 120 124 124 120 124 120 124
23 124 112 124 120 124 120 124 124 120 124 120 124
Примечание. Я получаю разные значения, я получаю ~ 120, поскольку 4 раза в час умножается на количество дней в каждом месяце (некоторые месяцы длиннее других)...
Хорошо поймал! Я исправил вопрос, чтобы отразить правильный ожидаемый результат.
Значит, cross_tab ведет подсчет по умолчанию (если вы не передадите aggfunc?)