为DataFrame中每个单元生成无缺失值的季度时间列
为多ID数据集生成无缺失的季度时间列
问题
我们有一个包含25个国家人均GDP的数据集,需要为每个id(1至25)生成对应time(1至61)的季度时间列(范围1993Q1至2008Q1),但现有代码生成的DataFrame中dates列存在大量NaT缺失值。
原代码
import requests import zipfile import io import pandas as pd import numpy as np from datetime import datetime from dateutil import relativedelta url = 'http://qed.econ.queensu.ca/jae/datasets/hsiao003/hcw-data.zip' filename = 'hcw-data.txt' r = requests.get(url) z = zipfile.ZipFile(io.BytesIO(r.content)) z.extractall() df = (pd.read_csv(url, sep='\t+', header=None, engine='python') .stack().rename_axis(['time', 'id']).rename('gdp').reset_index() .assign(time=lambda x: x['time'] + 1)) df['id'] = df['id']+1 df = df[['id', 'time', 'gdp']] df = df.sort_values(by=['id', 'time']) df = df.reset_index() start_date = datetime.strptime("1993-01-01", "%Y-%m-%d") # periods means how many dates you want date_list = pd.date_range(start_date, periods=61, freq='Q') df['dates'] = pd.DataFrame({'dates': date_list})
错误现象
生成的DataFrame中dates列仅前61行有值,后续行全部为NaT:
index id time gdp dates 0 0 1 1 0.0620 1993-03-31 1 25 1 2 0.0590 1993-06-30 2 50 1 3 0.0580 1993-09-30 3 75 1 4 0.0620 1993-12-31 4 100 1 5 0.0790 1994-03-31 ... .. ... ... ... 1520 1424 25 57 0.1110 NaT 1521 1449 25 58 0.1167 NaT 1522 1474 25 59 0.1002 NaT 1523 1499 25 60 0.1017 NaT 1524 1524 25 61 0.1238 NaT [1525 rows x 5 columns]
解决方案
问题根源
原代码生成的date_list仅包含61个日期,但数据集共有25个id×61个时间点=1525行。直接赋值时,只有前61行能匹配到日期,剩余行因无对应数据填充为NaT。此外,原代码还存在数据加载错误:用pd.read_csv(url)读取zip链接而非提取后的本地文本文件,会导致数据结构异常。
修改后的完整代码
import requests import zipfile import io import pandas as pd import numpy as np from datetime import datetime url = 'http://qed.econ.queensu.ca/jae/datasets/hsiao003/hcw-data.zip' filename = 'hcw-data.txt' # 下载并解压数据 r = requests.get(url) z = zipfile.ZipFile(io.BytesIO(r.content)) z.extractall() # 加载并整理数据集 df = (pd.read_csv(filename, sep='\t+', header=None, engine='python') # 读取本地解压后的文件 .stack().rename_axis(['time', 'id']).rename('gdp').reset_index() .assign(time=lambda x: x['time'] + 1)) df['id'] = df['id'] + 1 # 排序并清理冗余索引 df = df[['id', 'time', 'gdp']].sort_values(by=['id', 'time']).reset_index(drop=True) # 生成基础季度日期序列(1993Q1至2008Q1共61个季度) start_date = datetime.strptime("1993-01-01", "%Y-%m-%d") date_list = pd.date_range(start_date, periods=61, freq='Q') # 为每个id重复日期序列,填充所有行 df['dates'] = np.tile(date_list, 25) # 可选:将日期转换为"1993Q1"格式的季度字符串 df['quarter_label'] = df['dates'].dt.to_period('Q')
核心修改说明
- 修复数据加载:将
pd.read_csv(url)改为读取本地文件filename,确保正确解析文本数据。 - 批量生成重复日期:用
np.tile(date_list, 25)将61个季度日期重复25次,刚好匹配1525行数据,保证每个id的time1-61都对应正确日期。 - 清理冗余列:用
reset_index(drop=True)移除不必要的原索引列,简化DataFrame结构。 - 可选格式优化:通过
dt.to_period('Q')将日期转换为直观的季度标签(如1993Q1),方便后续分析。
内容的提问来源于stack exchange,提问作者Jared Greathouse
相关产品推荐
相关产品推荐

