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)
}
我有一个这种格式的大型天气数据集:
'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)
}