时间序列绘图

时间序列是一种非常常见的数据结构,在处理表格数据时,经常会遇到需要将时间序列作为横坐标的情形,这时,如果直接将读取到的时间序列传入到绘图系统,会导致横坐标乌漆嘛黑一团,因为系统将时间序列识别为一个字符串序列,每个值都是一个字符串,并不能很好地处理缩放和标注等问题,为了解决此问题,下面讲解一下使用Python绘制时间序列图像的过程,以及遇到的坑和解决办法。

1. 生成时间序列

1.1 使用datetime库函数生成

from datetime import datetime, timedelta

# 生成时间序列
start_time = datetime.strptime('2024-4-3 8:00:00', '%Y-%m-%d %H:%M:%S')
# 时间间隔:1min
delta = timedelta(minutes=1)
# 生成一个20min的时间序列
time_series = [start_time + i * delta for i in range(20)]

time_series

结果:

[datetime.datetime(2024, 4, 3, 8, 0),
 datetime.datetime(2024, 4, 3, 8, 1),
 datetime.datetime(2024, 4, 3, 8, 2),
 datetime.datetime(2024, 4, 3, 8, 3),
 datetime.datetime(2024, 4, 3, 8, 4),
 datetime.datetime(2024, 4, 3, 8, 5),
 datetime.datetime(2024, 4, 3, 8, 6),
 datetime.datetime(2024, 4, 3, 8, 7),
 datetime.datetime(2024, 4, 3, 8, 8),
 datetime.datetime(2024, 4, 3, 8, 9),
 datetime.datetime(2024, 4, 3, 8, 10),
 datetime.datetime(2024, 4, 3, 8, 11),
 datetime.datetime(2024, 4, 3, 8, 12),
 datetime.datetime(2024, 4, 3, 8, 13),
 datetime.datetime(2024, 4, 3, 8, 14),
 datetime.datetime(2024, 4, 3, 8, 15),
 datetime.datetime(2024, 4, 3, 8, 16),
 datetime.datetime(2024, 4, 3, 8, 17),
 datetime.datetime(2024, 4, 3, 8, 18),
 datetime.datetime(2024, 4, 3, 8, 19)]

2. 使用matplotlib.dates库生成

matplotlib也提供了一种产生时间序列的方法,在dates库里面

import matplotlib.dates as mdates
from datetime import datetime, timedelta
import matplotlib.pyplot as plt

# 时间起点
start_time = datetime.strptime('2024-4-3 8:00:00', '%Y-%m-%d %H:%M:%S')

# 时间终点
end_time = datetime.strptime('2024-4-3 9:12:00', '%Y-%m-%d %H:%M:%S')

# 时间间隔:1min
delta = timedelta(minutes=1)

time_series = mdates.drange(start_time, end_time, delta)
time_series

返回值:

array([19816.33333333, 19816.33402778, 19816.33472222, 19816.33541667,
       19816.33611111, 19816.33680556, 19816.3375    , 19816.33819444,
       ...
       19816.38055556, 19816.38125   , 19816.38194444, 19816.38263889,
       19816.38333333])

返回值是一个np.array,里面的每个数字都是一个时间点对应的结果,可以通过函数互相转换

# 将数字序列转换为时间序列
mdates.num2date(time_series)

输出:

[datetime.datetime(2024, 4, 3, 8, 0, tzinfo=datetime.timezone.utc),
 datetime.datetime(2024, 4, 3, 8, 1, tzinfo=datetime.timezone.utc),
 ...
 datetime.datetime(2024, 4, 3, 9, 11, tzinfo=datetime.timezone.utc),
 datetime.datetime(2024, 4, 3, 9, 12, tzinfo=datetime.timezone.utc)]

1.3. 读取并转换为时间序列

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# 读取文件
df = pd.read_excel(r'test.xlsx')

# 转换为时间序列
time_series = pd.to_datetime(df.iloc[:50, 0]).values
values = np.random.randint(0, len(time_series), len(time_series))
# 绘制时间序列
plt.plot(time_series, values, 'b-o')

查看数据

df.head()

结果:

在这里插入图片描述

上面图像的输出:
在这里插入图片描述

可以看到系统也是正确识别到了时间序列的格式

2. 绘制时间序列

2. 1使用plot绘制

from datetime import datetime, timedelta
import matplotlib.pyplot as plt
import random


n = 20

# 生成时间序列
start_time = datetime.strptime('2024-4-3 8:00:00', '%Y-%m-%d %H:%M:%S')
# 时间间隔:1min
delta = timedelta(minutes=1)
# 生成一个时间序列
time_series = [start_time + i * delta for i in range(n)]
values = [random.randint(0, 20) for _ in range(len(time_series))]

plt.plot(time_series, values, 'r--o')

输出:

在这里插入图片描述

注意到图像中已经正确识别到了时间序列,如果我们只是将字符串序列作为时间序列输入的话,会产生下面的效果

n = 20

# 生成时间序列
start_time = '2024-4-3 8:00:00'

delta = 1

# 生成一个时间序列
time_series = [start_time[:-2] + str(i * delta) for i in range(n)]

time_series

输出:

['2024-4-3 8:00:0',
 '2024-4-3 8:00:1',
 '2024-4-3 8:00:2',
 '2024-4-3 8:00:3',
 '2024-4-3 8:00:4',
 '2024-4-3 8:00:5',
 '2024-4-3 8:00:6',
 '2024-4-3 8:00:7',
 '2024-4-3 8:00:8',
 '2024-4-3 8:00:9',
 '2024-4-3 8:00:10',
 '2024-4-3 8:00:11',
 '2024-4-3 8:00:12',
 '2024-4-3 8:00:13',
 '2024-4-3 8:00:14',
 '2024-4-3 8:00:15',
 '2024-4-3 8:00:16',
 '2024-4-3 8:00:17',
 '2024-4-3 8:00:18',
 '2024-4-3 8:00:19']

2. 2 错误演示

import matplotlib.pyplot as plt
import random


n = 20

# 生成时间序列
start_time = '2024-4-3 8:00:00'

delta = 1

# 生成一个时间序列
time_series = [start_time[:-2] + str(i * delta) for i in range(n)]

values = [random.randint(0, 20) for _ in range(len(time_series))]

plt.plot(time_series, values, 'r-o')

输出:

在这里插入图片描述

从图像中可以横坐标并没有正确识别,每一个值都标注出来了,而且产生大面积的重合,为此,我们需要认识到,时间序列有专门的处理方式,直接使用字符串进行处理不可行。

3. 遇到的坑

使用mdates进行时间序列的生成,有的时候会因为浮点数的操作导致边界值发生错误,进而影响到整体,如下例:

start_time = datetime.strptime("2023-10-18 16:15:12.100", '%Y-%m-%d %H:%M:%S.%f')
delta = timedelta(microseconds=100)

for n in [3624, 3625, 3626, 3627, 3628, 3629]:
    series = mdates.drange(start_time, start_time + (n - 1) * delta, delta)
    print(f'n == {n}, length = {len(series)}')

输出结果:

n == 3624, length = 3624
n == 3625, length = 3624
n == 3626, length = 3626
n == 3627, length = 3627
n == 3628, length = 3627
n == 3629, length = 3629

从上面结果可以看到,当我们想要生成3625个数据时,实际上只有3624个;

当我们想要生成3628个数据时,此时只有3627个。

这时由于边界值的浮点数进行运算导致错误,原理类似于如下过程

start_point = 0.0
delta = 0.1
total_count = 20
time_series = [start_point + i * delta for i in range(total_count)]
time_series

输出结果:

[0.0,
 0.1,
 0.2,
 0.30000000000000004,
 0.4,
 0.5,
 0.6000000000000001,
 0.7000000000000001,
 0.8,
 0.9,
 1.0,
 1.1,
 1.2000000000000002,
 1.3,
 1.4000000000000001,
 1.5,
 1.6,
 1.7000000000000002,
 1.8,
 1.9000000000000001]

为了正确地产生想要的结果,最好使用确定的整数进行时间序列生成

比如下面的形式:

start_time = datetime.strptime("2023-10-18 16:15:12.100", '%Y-%m-%d %H:%M:%S.%f')
delta = timedelta(microseconds=100)
series = [start_time + i * delta for i in range(3625)]
len(series)

输出结果:

3625
  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值