Pandas 如何将宽日期数据转换为长格式

How to transform wide date data to long format in Pandas

我有一个这种格式的大型天气数据集:

'Daily Mean Temp for place name 2015'   # One table title per year
'Day'  'JAN'  'FEB'  'MAR'  ...  'DEC'
 1      23     26     21    ...   14
 2      20     30     22    ...   12
 3      26     27     22    ...   16
 ...    ...    ...    ...   ...   ...
 31     28     -      19    ...   11

我想把它变成这种格式:

'date'         'mean_temp'
2015-01-01      23
2015-01-02      20
2015-01-03      26

我一直无法找到解决方案,如果有任何建议,我将不胜感激?

首先映射您的月份,然后反转您的 df

import padas as pd

df.columns = [col.title() for col in df.columns]
df_unpivot = df.melt(id_vars=["Day"], var_name="month", value_name="mean_temp")

然后添加包含您的日期的新列(如果日期不存在则为 naT)

df_unpivot['date'] = pd.to_datetime(df_unpivot["Day"].map(str) + "-" + df_unpivot["month"] + "-2015", format='%d-%b-%Y', errors="coerce")

删除不需要的列和无效日期

df_unpivot.drop(["Day", "month"], axis=1, inplace=True)
df_unpivot.dropna(inplace=True)

将日期设置为索引

df_unpivot.set_index("date", inplace=True)

在一行中:

pd.concat([
    pd.concat((pd.Series(pd.date_range(start=f'{y}/{m}', end=pd.Timestamp(f'{y}/{m}') + pd.offsets.MonthEnd(0), freq='D'), name='Day'),
               df[c].rename('mean_temp')[:pd.Period(f'{y}/{m}').days_in_month]), axis=1)
    for y, df in sorted(temp_dfs.items())
    for m, c in enumerate(['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'], start=1)
], axis=0)

这里是结果:

         Day  mean_temp
0  2015-01-01           16
1  2015-01-02           29
2  2015-01-03           33
3  2015-01-04           28
4  2015-01-05           17
..        ...          ...
26 2019-12-27           32
27 2019-12-28           39
28 2019-12-29           -2
29 2019-12-30           39
30 2019-12-31            1

前面的代码假定 temp_dfs 是一个 dict,其中所有 DataFrame 按年份组织:键是所有可用的年份。我使用这段代码生成了一个示例 dict:

import pandas as pd
import numpy as np

temp_dfs = {
    y: pd.DataFrame(
        data=np.column_stack((np.arange(1, 32), np.random.randint(-3, 40, (31, 12)))),
        columns=['Day', 'JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC']
    ) for y in range(2015, 2020)
}