pandas resample时间序列数据处理(时间序列归一化,对齐,映射,空值填充)

pandas时间序列数据处理(时间序列归一化,对齐,映射,空值填充)

实现功能
  1. 将下面的csv数据对应到每间隔五分钟的时间序列上保证数据完整
  2. 详细描述: 时间区间数据对应 主要是将把每五分钟区间内的数据对应到五分钟倍数的区间上:example 将0,1 ,2分钟数据对应到00:00, 将3, 4, 5到10分钟之间的数据,将5, 6 ,7分钟数据对应到第五分钟,将7, 8 ,9, 10, 11 12 分钟数据对应到第10分钟, 13, 14, 15, 16, 17对应到第15分钟 依此类推
原始数据

在这里插入图片描述
将ct列对应成每五分钟一条数据的对齐

处理后数据

在这里插入图片描述

方法一 自定义时间判断函数

import pandas as pd
from datetime import datetime


def fill_data(df):
    # 均值填充pv
    df['pv'].fillna(value=df.mean(), inplace=True)
    # 前向填充 后向填充  _id  pid (均值填充id会出问题)
    df.fillna(method='bfill', inplace=True)
    df.fillna(method='ffill', inplace=True)
    return df


def merge_type_transform(df, tran_list):
    # 处理merge后的类型变化问题 float >>>> str
    df[tran_list] = df[tran_list].astype('str')
    for i in tran_list:
        df[i] = df[i].apply(lambda x: x.replace('.0', '').strip())
    #  一些价格数据或者短数字转字符串可用以下数据
    # 方法一
    # df['price'] = df['price'].map(lambda x:str(x))))
    # 方法二
    # df['price'] = df['price'].astype('str'))
    return df


def time_seq_map(df, ymd_time=None):
    """
    时间对齐  数据填充
    """
    # 手动传入时间
    time = pd.date_range(ymd_time + ' 00:00:00', ymd_time + ' 23:59:59', freq="5min")
    # 自动提取时间
    # extract_date_df = df.loc[:1, 'ct'].apply(lambda x: x.strftime('%Y-%m-%d'))
    # time = pd.date_range(extract_date_df[0] + ' 00:00:00', extract_date_df[0] + ' 23:59:59', freq="5min")
    # 生成一个标准每五分钟一行的时间序列dataframe
    df1 = pd.DataFrame({'ct1': time})
    # 与原始数据合并
    df = df.merge(df1, left_on='ct', right_on='ct1', how='right', sort='ct1')
    del df['ct']
    df.rename(columns={'ct1': 'ct'}, inplace=True)
    # 数据填充
    seq_map_df = fill_data(df)
    # 数据类型转化
    fina_df = merge_type_transform(seq_map_df, tran_list=['pid'])
    return fina_df


def _time_standardize_strategy(x):
    """
    自定义的一个时间函数:
    时间区间数据对应 主要是将把每五分钟区间内的数据对应到五分钟倍数的区间上:example 将0,1 ,2分钟数据对应到00:00, 将3, 4, 5到10分钟之间的数据,将5, 6 ,7分钟数据对应到第五分钟,将7, 8 ,9, 10, 11 12 分钟数据对应到第10分钟, 13, 14, 15, 16, 17对应到第15分钟 依此类推
    """
    hour = x.hour
    minute = x.minute
    second_ret = 0
    if minute % 5 >= 3:
        minute_new = (minute // 5 + 1) * 5
    else:
        minute_new = (minute // 5) * 5

    if minute_new == 60:
        minute_ret = 0
        hour_ret = hour + 1
        if hour_ret == 24:
            # 只是针对当天(最大时间23:55:00) example: 2021-07-26 23:59:59 ==>> 2021-07-26 23:55:00
            hour_ret = 23
            minute_ret = 55
            day_ret = x.day
            # day是连续性天数  example: 2021-07-26 23:59:59 ==>> 2021-07-27 00:00:00
            # hour_ret = 0
            # day_ret = x.day + 1
        else:
            day_ret = x.day
    else:
        minute_ret = minute_new
        hour_ret = hour
        day_ret = x.day
    return datetime(x.year, x.month, day_ret, int(hour_ret), int(minute_ret), int(second_ret))



def detail_time_series(df, null_thre=0.9):
    """
    时间归一化主函数
    """
    # 先对数据做时间序列去重
    df = df.copy()
    df = df.drop_duplicates(subset=['ct'])
    # 将ct变为datetime
    df.loc[:, 'ct'] = pd.to_datetime(df['ct'])

    df['ct'] = df['ct'].apply(_time_standardize_strategy)
    # 时间序列字段去重
    df = df.drop_duplicates(subset=['ct'])
    print(df)
    # 将索引类型改成 DatetimeIndex  将ct设置程索引  采样统计需要时间序列作为索引
    df.index = pd.DatetimeIndex(df.ct, name='index')
    # 空值统计 设定阈值
    df1 = df.resample('24H').count()
    # 将空值少于百分之10的时间list提取出来
    index_list = df1.index[df1['ct'] > int(len(df1['ct']) * null_thre)]
    df_list = []
    for time_str in index_list:
        ymd_time = time_str.strftime('%Y-%m-%d')
        day_data = df[ymd_time]
        stand_time_dfs = day_data.reset_index(drop=True)
        # 时间序列对其 空值用均值填充
        final_df = time_seq_map(stand_time_dfs, ymd_time)
        df_list.append(final_df)
    return df_list

# 读取原始数据
df = pd.read_csv('./bbb.csv')

df_list = detail_time_series(df)
# 将多个id对应好的数据合并成一个DataFrame
df = pd.concat(df_list, ignore_index=True)
print('最终数据', df)

方法二 pandas resample

import pandas as pd

def fill_data(df):
    # 均值填充pv
    df['pv'].fillna(value=df.mean(), inplace=True)
    # 前向填充 后向填充  _id  pid (均值填充id会出问题)
    df.fillna(method='bfill', inplace=True)
    df.fillna(method='ffill', inplace=True)
    return df


def merge_type_transform(df, tran_list):
    # 处理merge后的类型变化问题 float >>>> str
    df[tran_list] = df[tran_list].astype('str')
    for i in tran_list:
        df[i] = df[i].apply(lambda x: x.replace('.0', '').strip())
    #  一些价格数据或者短数字转字符串可用以下数据
    # 方法一
    # df['price'] = df['price'].map(lambda x:str(x))))
    # 方法二
    # df['price'] = df['price'].astype('str'))
    return df


def time_seq_map(df, ymd_time=None):
    """
    时间对齐  数据填充
    """
    # 手动传入时间
    time = pd.date_range(ymd_time + ' 00:00:00', ymd_time + ' 23:59:59', freq="5min")
    # 自动提取时间
    # extract_date_df = df.loc[:1, 'ct'].apply(lambda x: x.strftime('%Y-%m-%d'))
    # time = pd.date_range(extract_date_df[0] + ' 00:00:00', extract_date_df[0] + ' 23:59:59', freq="5min")
    # 生成一个标准每五分钟一行的时间序列dataframe
    df1 = pd.DataFrame({'ct1': time})
    # 与原始数据合并
    df = df.merge(df1, left_on='ct', right_on='ct1', how='right', sort='ct1')
    del df['ct']
    df.rename(columns={'ct1': 'ct'}, inplace=True)
    seq_map_df = fill_data(df)
    fina_df = merge_type_transform(seq_map_df, tran_list=['pid'])
    return fina_df.drop_duplicates(subset=['ct'])
    # return fina_df


def detail_time_series(df, null_thre):
    """
    时间归一化
    """
    # 先对数据做时间序列去重
    df = df.copy()
    df = df.drop_duplicates(subset=['ct'])
    # 将ct变为datetime
    df.loc[:, 'ct'] = pd.to_datetime(df['ct'])
    # 将索引类型改成 DatetimeIndex
    df.index = pd.DatetimeIndex(df.ct)
    # 做第一遍判断
    df1 = df.resample('24H').count()
    index_list = df1.index[df1['pid'] > int(len(df1['pid']) * null_thre)]
    time_list = [x.strftime('%Y-%m-%d') for x in index_list]
    print(time_list)

    df_list = []
    for time_str in index_list:
        ymd_time = time_str.strftime('%Y-%m-%d')
        day_data = df[ymd_time]
        # 时间归一化 间隔5分钟
        stand_time_df = day_data.resample(rule='5T').ffill()
        del stand_time_df['ct']
        # 将时间序列索引变成列 在重置索引
        stand_time_dfs = stand_time_df.rename_axis('ct').reset_index()
        # 时间序列对其 空值用均值填充
        final_df = time_seq_map(stand_time_dfs, ymd_time)
        df_list.append(final_df)
    return df_list


df = pd.read_csv('./bbb.csv')

df_list = detail_time_series(df, 0.9)  # 空值少于10%均值填充
df = pd.concat(df_list, ignore_index=True)
print(df)
  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BRYTLEVSON

打赏的都是天使,创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值