在数据分析场景中,Pandas的日期索引是处理时间序列数据的核心结构,很多数据集会将时间作为索引来方便按时间维度筛选、聚合数据。实际处理时,我们既需要从日期索引中提取年、月、日、星期等维度信息用于后续分析,也需要对数据中存在的NaN缺失值进行合理填充,保证数据完整性。

日期索引的基础创建与校验
首先我们需要确认数据的索引是否为日期类型,如果不是需要先转换,避免后续操作报错。可以通过pd.to_datetime方法将字符串类型的时间转换为日期格式,再设置为索引。
import pandas as pd
import numpy as np
# 构造示例数据
data = {
"value": [10, np.nan, 30, np.nan, 50, 60, np.nan]
}
# 创建日期范围作为索引
date_index = pd.date_range(start="2024-01-01", periods=7, freq="D")
df = pd.DataFrame(data, index=date_index)
# 校验索引是否为日期类型
print(df.index.dtype) # 输出 datetime64[ns] 说明是日期索引
从日期索引中高效提取信息
日期索引本身提供了多个属性,可以直接提取对应的时间维度信息,不需要额外调用复杂的函数,效率远高于遍历索引处理。
常用提取属性说明
| 属性名 | 说明 | 返回值类型 |
|---|---|---|
| year | 提取年份 | 整数 |
| month | 提取月份 | 整数,1-12 |
| day | 提取日 | 整数,1-31 |
| weekday | 提取星期几 | 整数,0代表周一,6代表周日 |
| hour | 提取小时 | 整数,0-23,仅当索引包含时间部分时可用 |
提取示例
我们可以直接将这些属性作为新列添加到DataFrame中,方便后续分组、筛选使用。
# 提取年、月、日、星期几信息 df["year"] = df.index.year df["month"] = df.index.month df["day"] = df.index.day df["weekday"] = df.index.weekday print(df.head()) # 输出结果示例: # value year month day weekday # 2024-01-01 10.0 2024 1 1 0 # 2024-01-02 NaN 2024 1 2 1 # 2024-01-03 30.0 2024 1 3 2 # 2024-01-04 NaN 2024 1 4 3 # 2024-01-05 50.0 2024 1 5 4
条件填充NaN的常用方法
填充NaN需要结合业务场景选择条件,常见的条件包括按时间相邻值填充、按同时间段历史数据填充、按固定值填充等,Pandas提供了对应的方法支持这些操作。
按时间相邻值填充
如果是时间序列数据,通常用前一个时间点或者后一个时间点的非缺失值填充当前NaN,使用fillna方法配合method参数即可实现。
# 用前一个非缺失值填充NaN,按时间顺序向前填充 df_ffill = df.copy() df_ffill["value"] = df_ffill["value"].fillna(method="ffill") print(df_ffill["value"]) # 输出: # 2024-01-01 10.0 # 2024-01-02 10.0 # 2024-01-03 30.0 # 2024-01-04 30.0 # 2024-01-05 50.0 # 2024-01-06 60.0 # 2024-01-07 60.0 # Name: value, dtype: float64 # 用后一个非缺失值填充NaN,按时间顺序向后填充 df_bfill = df.copy() df_bfill["value"] = df_bfill["value"].fillna(method="bfill")
按同时间段历史数据填充
如果数据有周期性,比如每年同月份的数值规律相似,可以提取月份维度后,按月份分组填充该月份的历史均值。
# 先提取月份信息,再按月份分组计算均值,填充对应月份的NaN
df_month_fill = df.copy()
df_month_fill["month"] = df_month_fill.index.month
# 计算每个月份的非缺失均值
month_mean = df_month_fill.groupby("month")["value"].mean()
# 遍历填充NaN
for month, mean_val in month_mean.items():
mask = (df_month_fill["month"] == month) & (df_month_fill["value"].isna())
df_month_fill.loc[mask, "value"] = mean_val
print(df_month_fill["value"])
自定义条件填充
如果有更复杂的填充条件,比如仅填充工作日的数据,周末的NaN保留,可以结合布尔索引实现。
# 仅填充工作日的NaN,周末的NaN不处理 df_custom_fill = df.copy() # 工作日为0-4,周末为5-6 weekday_mask = df_custom_fill.index.weekday < 5 nan_mask = df_custom_fill["value"].isna() # 仅填充工作日且为NaN的位置,用前一个非缺失值填充 fill_mask = weekday_mask & nan_mask df_custom_fill.loc[fill_mask, "value"] = df_custom_fill["value"].fillna(method="ffill") print(df_custom_fill["value"])
操作注意事项
- 处理日期索引前一定要先校验索引类型,避免字符串索引导致提取属性时报错
- 填充NaN前建议先备份原始数据,避免填充后无法恢复原始缺失状态
- 如果数据量较大,优先使用Pandas内置的向量化操作,不要使用for循环遍历索引,提升处理效率
- 提取日期信息时,新增的列如果后续不需要可以及时删除,避免占用额外内存