Как пересчитать ежедневные данные в почасовые данные за все дни с помощью pandas? - PullRequest
4 голосов
/ 10 июля 2020

У меня есть df кадра данных, подобный приведенному ниже:

    city    datetime    value
0   city_a  2020-07-10  2
1   city_a  2020-07-11  5
2   city_b  2020-07-11  4

И я пытаюсь пересчитать ежедневные даты с частотой 6 часов (данные каждые 00 часов, 6 часов, 12 часов и 18 часов).

Следующий код дает мне почти тот результат, который я ожидал

my_df = my_df.set_index(['datetime', 'city'])
my_df = my_df.unstack(-1).resample('6H').pad()
my_df = my_df.stack().reset_index()
my_df = my_df[['city', 'datetime', 'value']]
my_df = my_df.sort_values(['city', 'datetime'])

Результат:

    city    datetime            value
0   city_a  2020-07-10 00:00:00 2.0
1   city_a  2020-07-10 06:00:00 2.0
2   city_a  2020-07-10 12:00:00 2.0
3   city_a  2020-07-10 18:00:00 2.0
4   city_a  2020-07-11 00:00:00 5.0
5   city_b  2020-07-11 00:00:00 4.0

Однако мы видим, что день 2020-07-11 еще не завершен . Я хотел бы, чтобы в выводе появлялись строки, включая 06:00:00, 12:00:00 и 18:00:00 от 2020-07-11.

Итак, мой ожидаемый результат должен быть:

    city    datetime            value
0   city_a  2020-07-10 00:00:00 2.0
1   city_a  2020-07-10 06:00:00 2.0
2   city_a  2020-07-10 12:00:00 2.0
3   city_a  2020-07-10 18:00:00 2.0
4   city_a  2020-07-11 00:00:00 5.0
6   city_a  2020-07-11 06:00:00 5.0
8   city_a  2020-07-11 12:00:00 5.0
10  city_a  2020-07-11 18:00:00 5.0
5   city_b  2020-07-11 00:00:00 4.0
7   city_b  2020-07-11 06:00:00 4.0
9   city_b  2020-07-11 12:00:00 4.0
11  city_b  2020-07-11 18:00:00 4.0

Есть ли элегантный способ сделать это с помощью Pandas?

Код для генерации фрейма данных:

my_df = pd.DataFrame(data = {
    'city': ['city_a', 'city_a', 'city_b'],
    'datetime': 
[pd.to_datetime('2020/07/10'),pd.to_datetime('2020/07/11'),pd.to_datetime('2020/07/11')],
    'value': [2,5,4]
})

Ответы [ 2 ]

5 голосов
/ 10 июля 2020

Используйте :

# STEP A
df1 = (df.groupby('city')['datetime'].max() + pd.Timedelta(days=1)).reset_index()

# STEP B
df1 = pd.concat([df, df1]).set_index('datetime')

# STEP C
df1 = df1.groupby('city', as_index=False).resample('6H').ffill()

# STEP D
df1 = df1.reset_index().drop('level_0', 1).dropna(subset=['value'])

Подробности:

ШАГ A: Используйте DataFrame.groupby для группировки фрейм данных city, чтобы определить максимальное значение даты в каждой группе и добавить 1 day к максимальному значению каждой группы, это потребуется для повторной выборки фрейма данных.

# print(df1)
     city   datetime
0  city_a 2020-07-12
1  city_b 2020-07-12

ШАГ B: Использование pd.concat, чтобы объединить исходный фрейм данных df с вновь созданным фреймом данных df1, это потому, что мы должны пересчитать фрейм данных в STEP C.

# print(df1)
              city  value
datetime                 
2020-07-10  city_a    2.0
2020-07-11  city_a    5.0
2020-07-11  city_b    4.0
2020-07-12  city_a    NaN
2020-07-12  city_b    NaN

STEP C: Используя DataFrame.resample, повторно выполните выборку фрейма данных, сгруппированного на city, с частотой 6H и используйте ffill для прямого заполнения значений.

# print(df1)
                         city  value
  datetime                          
0 2020-07-10 00:00:00  city_a    2.0
  2020-07-10 06:00:00  city_a    2.0
  2020-07-10 12:00:00  city_a    2.0
  2020-07-10 18:00:00  city_a    2.0
  2020-07-11 00:00:00  city_a    5.0
  2020-07-11 06:00:00  city_a    5.0
  2020-07-11 12:00:00  city_a    5.0
  2020-07-11 18:00:00  city_a    5.0
  2020-07-12 00:00:00  city_a    NaN
1 2020-07-11 00:00:00  city_b    4.0
  2020-07-11 06:00:00  city_b    4.0
  2020-07-11 12:00:00  city_b    4.0
  2020-07-11 18:00:00  city_b    4.0
  2020-07-12 00:00:00  city_b    NaN

STEP D: Наконец, используйте DataFrame.reset_index и удалите неиспользуемые столбцы, используя DataFrame.drop вдоль axis=1, также используйте DataFrame.dropna, чтобы удалить строки с помощью NaN значения в столбце value.

# print(df1)
              datetime    city  value
0  2020-07-10 00:00:00  city_a    2.0
1  2020-07-10 06:00:00  city_a    2.0
2  2020-07-10 12:00:00  city_a    2.0
3  2020-07-10 18:00:00  city_a    2.0
4  2020-07-11 00:00:00  city_a    5.0
5  2020-07-11 06:00:00  city_a    5.0
6  2020-07-11 12:00:00  city_a    5.0
7  2020-07-11 18:00:00  city_a    5.0
9  2020-07-11 00:00:00  city_b    4.0
10 2020-07-11 06:00:00  city_b    4.0
11 2020-07-11 12:00:00  city_b    4.0
12 2020-07-11 18:00:00  city_b    4.0
4 голосов
/ 10 июля 2020

Единственный способ, который я вижу, - это добавить пустую строку, имеющую datetime, равную последней существующей datetime + один день. Тогда вы можете сделать почти то же самое (pivot - удобный способ заменить set_index и разложить стек).

# adding a row where datetime corresponds to the max datetime + 1 day
df.loc[len(df), 'datetime'] = df.datetime.max() + pd.Timedelta(days=1)

# pivot to replace set_index & unstack
df = (df.pivot(index='datetime', columns='city')
   .resample('6H')
   .pad(3)
   .stack()
   .reset_index()
   .sort_values(['city', 'datetime']))

df[['city', 'datetime', 'value']]

    city    datetime    value
0   city_a  2020-07-10 00:00:00 2.0
1   city_a  2020-07-10 06:00:00 2.0
2   city_a  2020-07-10 12:00:00 2.0
3   city_a  2020-07-10 18:00:00 2.0
4   city_a  2020-07-11 00:00:00 5.0
6   city_a  2020-07-11 06:00:00 5.0
8   city_a  2020-07-11 12:00:00 5.0
10  city_a  2020-07-11 18:00:00 5.0
5   city_b  2020-07-11 00:00:00 4.0
7   city_b  2020-07-11 06:00:00 4.0
9   city_b  2020-07-11 12:00:00 4.0
11  city_b  2020-07-11 18:00:00 4.0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...