python 时间序列处理

数据说明:’./data/raw/pm25.csv’文件为某地2017年一段时间内的PM2.5的每小时监测数据,数据按时间顺序记录(从2017-01-01 00:00:00开始,中间不间断),由于各种原因造成了某些时刻的数据缺失。

要求:

1.利用已有的记录数据进行建模,将缺失值填充完整,评估指标采用RMSE、MAE和;

2.尝试多种方法进行建模对比各种模型的性能;

3.希望你不要直接用中值、均值、前一时刻、后一时刻等常数填充法进行填充(方法对比中可用做简单对比,如表 2所示);

4.将数据填充完整后保存至’pm25_predicted.csv’文件(只保存缺失时刻的数据,不按要求则作废),数据格式如表 3所示(列名、文件名不按要求则作废)。

题解:

(1)完成时间序列缺失数据填充,一般来说有如下几种方式:常数填充有均值填充,中位数填充,众数填充,前一时刻和后一时刻填充,传统回归模型方式有自回归模型,移动平均模型,自回归移动平均模型和差分自回归移动平均模型,一般采用插值法填充数据,插值办法一般有滑动平均插值,线性插值,拉格朗日多项式插值;

(2)每个函数对应一种办法,先将数据用pandas从csv文件中读取为df,然后进行数据插值的算法操作,最后将插值后的数据集用matplotlib呈现出来,最后将插值的数据转化为df,用pandas重新写回csv之中;

代码:

1.time_series_fill.py

# -*- coding:utf-8 -*-

from pandas.compat import reduce

__author__ = 'gin.chen'

import pandas as pd

import numpy as np

import matplotlib.pyplot as plt

from scipy.interpolate import lagrange

# from fbprophet import Prophet

#

# 加载数据

def load_data():

    df = pd.read_csv('F:/muke/super_mali/data/raw/pm25.csv')

    # return df.head(100)

    return df

# 画散点图

def draw_scatte_diagram(df):

    plt.plot(df['index'].to_list(), df['PM2.5'].to_list())

    plt.show()

# 均值填充

def mean_method():

    df = load_data()

    df.fillna(df['PM2.5'].mean(), inplace=True)

    draw_scatte_diagram(df)

# 中位数填充

def median_method():

    df = load_data()

    df.fillna(df['PM2.5'].median(), inplace=True)

    draw_scatte_diagram(df)

# 众数填充

def mode_method():

    df = load_data()

    df.fillna(df['PM2.5'].mode(), inplace=True)

    draw_scatte_diagram(df)

# 前一时刻填充

def ffill_method():

    df = load_data()

    df['PM2.5'].fillna(method='ffill', inplace=True)

    draw_scatte_diagram(df)

# 后一时刻填充

def bfill_method():

    df = load_data()

    df['PM2.5'].fillna(method='bfill', inplace=True)

    draw_scatte_diagram(df)

# 前后时刻平均值插值

def mean_by_before_after_method():

    df = load_data()

    # data_index = df['index'].to_list()

    # data_value = df['PM2.5'].to_list()

    fill = []

    for i in range(len(df)):

        if np.math.isnan(df.iloc[i - 1][1]):

            left = df.iloc[i - 2][1]

            for j in range(i, len(df)):

                if np.math.isnan(df.iloc[j][1]):

                    continue

                else:

                    right = df.iloc[j][1]

                    break

            df.iloc[i - 1, 1] = (left + right) / 2

            fill_tuple = i, df.iloc[i - 1][1]

            fill.append(fill_tuple)

    draw_scatte_diagram(df)

    df = pd.DataFrame(fill, columns=['index', 'PM2.5'])

    df.to_csv('pm25_predicted_mean.csv', index=False)

# 线性插值详细

def linear_detail(x1, y1, x2, y2):

    k = (y2 - y1) / (x2 - x1)

    b = y1 - k * x1

    return lambda x: b + k * x

# 线性插值

def linear_method():

    # global j

    df = load_data()

    fill = []

    for i in range(len(df)):

        if np.isnan(df.iloc[i][1]):

            for j in range(i, len(df)):

                if np.isnan(df.iloc[j][1]):

                    continue

                else:

                    break

            df.iloc[i, 1] = (linear_detail(i, df.iloc[i - 1][1], j + 1, df.iloc[j][1]))(i + 1)

            fill_tuple = i + 1, df.iloc[i][1]

            fill.append(fill_tuple)

    draw_scatte_diagram(df)

    df = pd.DataFrame(fill, columns=['index', 'PM2.5'])

    df.to_csv('pm25_predicted_linear.csv', index=False)

# 平滑插值详细

def smooth_detail(series, pos, window=5):

    """

    :param series: 列向量

    :param pos: 被插值的位置

    :param window: 为取前后的数据个数

    :return:

    """

    y = series[list(range(pos - window, pos)) + list(range(pos + 1, pos + 1 + window))]  # 取数

    y = y[y.notnull()]

    return reduce(lambda a, b: a + b, y) / len(y)

# 平滑插值

def smooth_method(show=1):

    df_raw = load_data()

    df = df_raw['PM2.5'].copy()

    full = []

    for j in range(len(df)):

        if (df.isnull())[j]:  # 如果为空即插值。

            df[j] = smooth_detail(df, j)

            df_raw.loc[j, 'PM2.5'] = df[j]

            # print(j, df_raw.loc[j, 'index'], df_raw.loc[j, 'PM2.5'])

            full_tuple = df_raw.loc[j, 'index'], df_raw.loc[j, 'PM2.5']

            full.append(full_tuple)

    if show:

        draw_scatte_diagram(df_raw)

        df = pd.DataFrame(full, columns=['index', 'PM2.5'])

        df.to_csv('pm25_predicted_smooth.csv', index=False)

    return df_raw

# 拉格朗日插值详细

def lagrange_detail(series, pos, window=5):

    """

    :param series: 列向量

    :param pos: 被插值的位置

    :param window: 为取前后的数据个数

    :return:

    """

    y = series[list(range(pos - window, pos)) + list(range(pos + 1, pos + 1 + window))]  # 取数

    y = y[y.notnull()]  # 剔除空值

    return lagrange(y.index, list(y))(pos)  # 插值并返回插值结果

# 拉格朗日插值

def lagrange_method():

    df_raw = load_data()

    df = df_raw['PM2.5'].copy()

    full = []

    for j in range(len(df)):

        if (df.isnull())[j]:  # 如果为空即插值。

            df[j] = lagrange_detail(df, j)

            df_raw.loc[j, 'PM2.5'] = df[j]

            # print(j, df.loc[j, 'index'], df[j])

            full_tuple = df_raw.loc[j, 'index'], df_raw.loc[j, 'PM2.5']

            full.append(full_tuple)

    draw_scatte_diagram(df_raw)

    df = pd.DataFrame(full, columns=['index', 'PM2.5'])

    df.to_csv('pm25_predicted_lagrange.csv', index=False)

# 计算RMSE

def calculate_RMSE(target, prediction):

    error = []

    for i in range(len(target)):

        error.append(target[i] - prediction[i])

    return (sum([n * n for n in error]) / len(error)) ** 0.5

# 计算MAE

def calculate_MAE(target, prediction):

    error = []

    for i in range(len(target)):

        error.append(target[i] - prediction[i])

    return sum([abs(n) for n in error]) / len(error)

# 计算R-square

def calculate_R_Square(target, prediction):

    error = []

    a = calculate_MAE(target, prediction) * len(error)

    mean = np.mean(np.array(target))

    for i in range(len(target)):

        error.append(prediction[i] - mean)

    b = sum([n * n for n in error])

    return 1 - a / b

if __name__ == '__main__':

    # mean_method()

    # median_method()

    # mode_method()

    # ffill_method()

    # bfill_method()

    # mean_by_before_after_method()

    # linear_method()

    # lagrange_method()

    smooth_method()

2.fbprophet_fill.py

# -*- coding:utf-8 -*-

from pandas.io.sas.sas7bdat import _column

from time_series_fill import smooth_method

__author__ = 'gin.chen'

import pandas as pd

import numpy as np

import matplotlib.pyplot as plt

import datetime

from fbprophet import Prophet

if __name__ == '__main__':

    def load_data():

        # df = pd.read_csv('F:/muke/super_mali/data/raw/pm25.csv')

        # return df.head(100)

        df = smooth_method(0)

        return df.head(3129)

    df = load_data()

    first_value = datetime.datetime.strptime('2017-01-01 00:00:00', '%Y-%m-%d %H:%M:%S')

    for i in range(len(df)):

        df.iloc[i, 0] = (first_value + datetime.timedelta(hours=i)).strftime("%Y-%m-%d %H:%M:%S")

    # df = pd.DataFrame(, columns=['ds', 'y'])

    # df.to_csv('pm25_predicted_mean.csv', index=False)

    # print(df.iloc[1,0])

    df.rename(columns={'index': 'ds', 'PM2.5': 'y'}, inplace=True)

    m = Prophet()

    # df['y'] = np.log(df['y'])

    df = m.fit(df)

    future = m.make_future_dataframe(freq='H', periods=5428)

    future.tail()

    forecast = m.predict(future)

    forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail()

    fig1 = m.plot(forecast)

    fig2 = m.plot_components(forecast)

    plt.show()

运行结果图:


Mean


Median


Ffill_method 


Bfill_method 


Linear_method 


lagrange_method


smooth_method


Fbprophet实现 


日,周,月的趋势 

未完待续。。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容