R语言python时间序列处理

使用R和Python填充时间序列数据中的缺失值
本文介绍如何使用R和Python处理时间序列数据中的缺失值。通过创建连续的时间序列并使用`left_join`或`merge`函数,将缺失值自动填充为NA。在R中,利用`lubridate`包处理时间,并编写`create_time_seq`函数生成时间列表;在Python中,结合`datetime`和`pandas`库实现相同功能。

背景

最近一个读者问到了这样的一个问题:

  1. 有一个时间序列的数据。
  2. 每半小时记录一次数据,但有的地方有缺失,时间序列不完整。
  3. 需要对缺失的部分,填充为NA。
  4. 也就是缺少的时间要加到表哥里面,缺失的值是要填充为NA

好久没写R代码了,这里写一写吧。

先创建一个样本

library(tidyverse)


sample_data = tibble('mytime'=c(
  lubridate::as_datetime("2022-01-01 12:30:00"),
  lubridate::as_datetime("2022-01-01 13:30:00"),
  lubridate::as_datetime("2022-01-01 14:00:00"),
  lubridate::as_datetime("2022-01-01 15:30:00")
),
'value' = c(1,4,5,8),
'value2' = c(3,4,5,6),
'value3' = c(20, 20, 30, 40))

sample_data

# # A tibble: 4 × 4
#   mytime              value value2 value3
#   <dttm>              <dbl>  <dbl>  <dbl>
# 1 2022-01-01 12:30:00     1      3     20
# 2 2022-01-01 13:30:00     4      4     20
# 3 2022-01-01 14:00:00     5      5     30
# 4 2022-01-01 15:30:00     8      6     40

可以看出来上面的数据中:

  1. 数据的时间范围是从2022-01-01 12:302022-01-01 15:30的。
  2. 每隔30分钟就记录一次。
  3. 但是缺少了13:0014:3015:00时刻的数据。

解决办法

思路很简单:

  1. 就是创建一个连续的、每隔30分钟的、完整的时间列表。
  2. 然后把列表放到数据框里面。
  3. 然后使用left_join的特性,直接对表格进行关联即可,会自动填充NA

1.创建连续的时间列表

create_time_seq <- function(start_date, end_date, by){
  n = lubridate::interval(start = start_date, end = end_date) / by 
  
  res <- start_date + by * c(0:n)
  return(res)
  
}

time_seq <- create_time_seq(
  start_date = sample_data %>% pull(mytime) %>% min(),
  end_date = sample_data %>% pull(mytime) %>% max(),
  by = lubridate::minutes(30)
)

time_seq
# [1] "2022-01-01 12:30:00 UTC" "2022-01-01 13:00:00 UTC" "2022-01-01 13:30:00 UTC"
# [4] "2022-01-01 14:00:00 UTC" "2022-01-01 14:30:00 UTC" "2022-01-01 15:00:00 UTC"
# [7] "2022-01-01 15:30:00 UTC"

这里的难点主要是在create_time_seq函数里面,这个函数的主要功能有:

  1. 这个函数计算了从开始时间结束时间,按照步长为by的时间节点的个数。
  2. 然后把这个范围内的节点都计算出来。保证一个节点都不少。

最后time_seq就是按照样本数据的时间范围,和要求的步长,生成了一串符合要求的时间序列列表。

2. 关联

tibble(
  'true_time' = time_seq
) %>% left_join(
  y=sample_data,
  by=c('true_time' = 'mytime')
)

# # A tibble: 7 × 4
#   true_time           value value2 value3
#   <dttm>              <dbl>  <dbl>  <dbl>
# 1 2022-01-01 12:30:00     1      3     20
# 2 2022-01-01 13:00:00    NA     NA     NA
# 3 2022-01-01 13:30:00     4      4     20
# 4 2022-01-01 14:00:00     5      5     30
# 5 2022-01-01 14:30:00    NA     NA     NA
# 6 2022-01-01 15:00:00    NA     NA     NA
# 7 2022-01-01 15:30:00     8      6     40

把列表放到数据框里面,然后巧妙的使用left_join函数,对两个表进行关联,从而对缺失的节点直接进行填充。

总结

  1. 这个只是一个非常小的,对R语言的时间做处理的小案例。
  2. 建议大家在R中处理时间的时候,最好都用lubridate包来处理。
  3. 巧妙的生成时间序列、然后使用数据框来关联,这个思想在python里面也是常见的。如果用python写的话,其实就是使用列表推导式、datetime包、pandas包来做。

我就知道你不信,我给你写过代码就知道了

python版本

# part1
from datetime import datetime,timedelta
import pandas as pd

# part 2
sample_date = pd.DataFrame({'mytime':[datetime.strptime(i,'%Y-%m-%d %X') for i in ['2022-01-01 12:30:00', '2022-01-01 13:30:00', '2022-01-01 14:00:00', '2022-01-01 15:30:00']],
              'value1':[1,4,5,8], 'value2':[3,4,5,6], 'value3':[20, 20, 30, 40]})
sample_date

#                 mytime  value1  value2  value3
# 0 2022-01-01 12:30:00       1       3      20
# 1 2022-01-01 13:30:00       4       4      20
# 2 2022-01-01 14:00:00       5       5      30
# 3 2022-01-01 15:30:00       8       6      40

# part 3
def create_time_seq(start_date, end_date, by):
    n = (end_date - start_date ) / by
    res = [start_date + by * i for i in range(int(n+1))]
    return res

time_seq = create_time_seq(start_date=sample_date['mytime'].min(),
                           end_date=sample_date['mytime'].max(),
                           by=timedelta(minutes=30))
time_seq

# [Timestamp('2022-01-01 12:30:00'), 
# Timestamp('2022-01-01 13:00:00'), 
# Timestamp('2022-01-01 13:30:00'), 
# Timestamp('2022-01-01 14:00:00'), 
# Timestamp('2022-01-01 14:30:00'), 
# Timestamp('2022-01-01 15:00:00'), 
# Timestamp('2022-01-01 15:30:00')]

# part 4

pd.DataFrame({'true_time':time_seq}).pipe(
    lambda x: x.merge(
        right=sample_date,
        how='left',
        left_on=['true_time'],
        right_on=['mytime']
    )
).pipe(
    lambda x: x.drop(columns=['mytime'])
)

#             true_time  value1  value2  value3
# 0 2022-01-01 12:30:00     1.0     3.0    20.0
# 1 2022-01-01 13:00:00     NaN     NaN     NaN
# 2 2022-01-01 13:30:00     4.0     4.0    20.0
# 3 2022-01-01 14:00:00     5.0     5.0    30.0
# 4 2022-01-01 14:30:00     NaN     NaN     NaN
# 5 2022-01-01 15:00:00     NaN     NaN     NaN
# 6 2022-01-01 15:30:00     8.0     6.0    40.0

最终

  1. 没想到吧,学R的时候,竟然还学了PYTHON
  2. 有学习交流群,如果想加入本群的,想办法找到我~

阅读更多

list

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

yuanzhoulvpi

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值