当前位置: 首页 > article >正文

Python数据分析NumPy和pandas(三十五、时间序列数据基础)

时间序列数据是许多不同领域的结构化数据的重要形式,例如金融、经济、生态学、神经科学和物理学。在许多时间点重复记录的任何内容都会形成一个时间序列。许多时间序列是固定频率的,也就是说,数据点根据某些规则定期出现,例如每 15 秒、每 5 分钟或每月一次。时间序列也可以是不规则的,没有固定的时间单位或单位之间的偏移量。如何标记和引用时间序列数据取决于应用程序,常用的有以下几种标记时间序列的方式:

时间戳(Timestamps):特定的时刻。

固定期间(Fixed periods):例如 2020 年 1 月的整个月,或 2023 年全年。

时间间隔(Intervals of time):由开始和结束时间戳指示。周期可以被认为是间隔的特殊情况。

实验或已用时间(Experiment or elapsed time):每个时间戳都是相对于特定开始时间的时间度量,从 0 开始(例如,饼干放入烤箱后每秒烘烤的直径)。

最简单的时间序列是按 timestamp 索引。pandas 支持基于 timedeltas 的索引,这是表示 experiment 或 elapsed time 的有用方法,可以在 pandas 官方文档中了解更多信息。

pandas 提供了许多内置的时序工具和算法。可以有效地处理大型时间序列,并对不规则和固定频率的时间序列进行切片和切块、聚合和重新采样。其中一些工具对于金融和经济应用程序很有用,也可以使用它们来分析服务器日志数据等。

Python 标准库包括日期和时间数据的数据类型,以及与日历相关的功能。datetime、time 和 calendar 模块实现了主要的基础功能。datetime.datetime 类型(或简称 datetime)使用的非常频繁:

from datetime import datetime

now = datetime.now()
print(now)
print(now.year, now.month, now.day)

now输出当前年月日时分秒毫秒:2024-11-17 11:58:02.773699

now.year, now.month, now.day 输出:2024 11 17

datetime 将日期和时间存储到微秒。datetime.timedelta,或简称 timedelta,表示两个 datetime 对象之间的时间差异:

from datetime import datetime

delta = datetime(2024, 11, 17) - datetime(2023, 9, 1, 8, 15)
print(delta)
print(delta.days, delta.seconds)

delta输出:442 days, 15:45:00

delta.days, delta.seconds 输出:442      56700

上面输出的delta是datetime.timedelta对象,我们可以将 timedelta 或其倍数加(或减)到 datetime 对象中,以产生新的移位对象:

from datetime import datetime, timedelta

start = datetime(2024, 1, 6)
res1 = start + timedelta(12)
res2 = start - 2 * timedelta(12)
print(res1)
print(res2)

res1输出的结果是start日期+12天的日期:2024-01-18 00:00:00

res2输出的结果是start日期-24天的日期:2023-12-13 00:00:00

下图列表是datatime模块中包含的数据类型:

一、String 和 Datetime 类型转换

可以使用 str 或 strftime 方法将 datetime 对象和 pandas Timestamp 对象(稍后将学习)格式化为字符串,并传递字符串格式规范:

from datetime import datetime, timedelta

stamp = datetime(2024, 1, 6)
print(str(stamp)) #输出 2024-01-06 00:00:00

print(stamp.strftime("%Y-%m-%d")) # 输出 2024-01-06

以下是日期格式规范的列表截图(自己翻译学习使用):

可以使用许多相同的格式代码通过 datetime.strptime 将字符串转换为日期(但某些代码,如 %F,不能使用):

from datetime import datetime, timedelta

value = "2024-01-06"
print(datetime.strptime(value, "%Y-%m-%d")) # 输出:2024-01-06 00:00:00

datestrs = ["7/6/2024", "8/6/2024"]
res = [datetime.strptime(x, "%m/%d/%Y") for x in datestrs]
print(res) # 输出:[datetime.datetime(2024, 7, 6, 0, 0), datetime.datetime(2024, 8, 6, 0, 0)]

pandas 通常面向日期数组使用,无论是用作轴索引还是 DataFrame 中的列。pandas.to_datetime 方法解析许多不同类型的日期表示形式。可以快速解析 ISO 8601 等标准日期格式:

import pandas as pd

datestrs = ["2024-07-06 12:00:00", "2024-08-06 00:00:00"]
res = pd.to_datetime(datestrs)
print(res) # 输出:DatetimeIndex(['2024-07-06 12:00:00', '2024-08-06 00:00:00'], dtype='datetime64[ns]', freq=None)

# 处理应被视为缺失的值(None、空字符串等):
idx = pd.to_datetime(datestrs + [None])
print(idx) # 输出:DatetimeIndex(['2024-07-06 12:00:00', '2024-08-06 00:00:00', 'NaT'], dtype='datetime64[ns]', freq=None)

print(idx[2]) # 输出:NaT

print(pd.isna(idx)) # 输出:[False False  True]

以上代码输出请看相关注释。

NaT (Not a Time) 是 pandas 的时间戳数据的 null 值。下面列表图片是特定于区域设置的日期格式:

二、Time Series Basics

pandas 中的一种基本时间序列对象是由时间戳索引的 Series,它通常在 pandas 之外表示为 Python 字符串或日期时间对象。与其他 Series 一样,具有时间序列索引的Series对象之间的算术运算会自动在日期上对齐。pandas 使用 NumPy 的 datetime64 数据类型以纳秒分辨率存储时间戳。DatetimeIndex 中的标量值是 pandas Timestamp 对象。看如下示例:

import numpy as np
import pandas as pd
from datetime import datetime, timedelta

np.random.seed(12345)

dates = [datetime(2024, 1, 2), datetime(2024, 1, 5),
         datetime(2024, 1, 7), datetime(2024, 1, 8),
         datetime(2024, 1, 10), datetime(2024, 1, 12)]
ts = pd.Series(np.random.standard_normal(6), index=dates)
print(ts)

# 在后台,这些 datetime 对象已被放入 DatetimeIndex 中:
print(ts.index)

# 具有时间序列索引的Series对象之间的算术运算会自动在日期上对齐
# ts[::2] 在 ts 中步长为2选择元素。
res = ts + ts[::2]
print(res)

# pandas 使用 NumPy 的 datetime64 数据类型以纳秒分辨率存储时间戳
print(ts.index.dtype)

# DatetimeIndex 中的标量值是 pandas Timestamp 对象
stamp = ts.index[0]
print(stamp)

Series对象ts输出:

ts.index输出:

DatetimeIndex(['2024-01-02', '2024-01-05', '2024-01-07', '2024-01-08',
               '2024-01-10', '2024-01-12'],
              dtype='datetime64[ns]', freq=None)

ts + ts[::2] 运算输出:

ts.index.dtype 输出ts的索引数据类型:datetime64[ns]

ts.index[0] 输出第0个索引的值(标量值):2024-01-02 00:00:00

在大多情况下,pandas.Timestamp能够替换datetime对象使用,反之则不然,因为 pandas.Timestamp 可以存储纳秒精度数据,而 datetime 最多只能存储微秒。另外, pandas.Timestamp 可以存储频率信息(如果有)并能进行时区转换和其他类型的操作。

索引、选择、子集(Indexing, Selection, Subsetting)

根据标签为数据编制索引和选择数据时,时间序列的行为与其他序列是相似的:

import numpy as np
import pandas as pd
from datetime import datetime, timedelta

np.random.seed(12345)

dates = [datetime(2024, 1, 2), datetime(2024, 1, 5),
         datetime(2024, 1, 7), datetime(2024, 1, 8),
         datetime(2024, 1, 10), datetime(2024, 1, 12)]
ts = pd.Series(np.random.standard_normal(6), index=dates)
print(ts)

stamp = ts.index[0]
print(ts[stamp])

# 为方便起见,可以传递可解释为 date 的字符串
print(ts["2024-01-10"])

ts[stamp]输出:-0.20470765948471295

ts["2024-01-10"]输出:1.9657805725027142

对于较长的时间序列,可以传递一年或仅传递一年和月份来轻松选择数据切片:

import numpy as np
import pandas as pd

np.random.seed(12345)

longer_ts = pd.Series(np.random.standard_normal(1000),
                      index=pd.date_range("2022-01-01", periods=1000))
print(longer_ts)
print(longer_ts["2023"])

longer_ts输出:

longer_ts["2023"]输出:

这里,longer_ts["2023"]中字符串 “2023” 被解释为年份并选择该时间段。如果指定月份,这也适用,例如:

import numpy as np
import pandas as pd

np.random.seed(12345)

longer_ts = pd.Series(np.random.standard_normal(1000),
                      index=pd.date_range("2022-01-01", periods=1000))
print(longer_ts)
print(longer_ts["2023"])
print(longer_ts["2023-06"])

longer_ts["2023-06"]输出:

使用 datetime 对象进行切片也有用,我们看如下代码示例:

import numpy as np
import pandas as pd
from datetime import datetime

np.random.seed(12345)

dates = [datetime(2024, 1, 2), datetime(2024, 1, 5),
         datetime(2024, 1, 7), datetime(2024, 1, 8),
         datetime(2024, 1, 10), datetime(2024, 1, 12)]
ts = pd.Series(np.random.standard_normal(6), index=dates)
print(ts)

print(ts[datetime(2024, 1, 7):])
print(ts[datetime(2024, 1, 7):datetime(2024, 1, 10)])

# 由于大多数时间序列数据是按时间顺序排序的,因此可以使用时间序列中未包含的时间戳进行切片以执行范围查询
# ts时间序列索引未包含值"2024-01-06"和"2024-01-11",下面执行范围查询
print(ts["2024-01-06":"2024-01-11"])

ts输出:

ts[datetime(2024, 1, 7):] 输出:

ts[datetime(2024, 1, 7):datetime(2024, 1, 10)]输出:

ts["2024-01-06":"2024-01-11"] 输出:

与之前一样,可以传递字符串 date、datetime 或 timestamp。请记住,以这种方式进行切片会在源时间序列上生成视图,就像切片 NumPy 数组一样。这意味着不会复制任何数据,并且对切片的修改将反映在原始数据中。

有一个等效的实例方法 truncate,它在两个日期之间对 Series 进行切片:

import numpy as np
import pandas as pd
from datetime import datetime

np.random.seed(12345)

dates = [datetime(2024, 1, 2), datetime(2024, 1, 5),
         datetime(2024, 1, 7), datetime(2024, 1, 8),
         datetime(2024, 1, 10), datetime(2024, 1, 12)]
ts = pd.Series(np.random.standard_normal(6), index=dates)

print(ts.truncate(after="2024-01-09"))

ts.truncate(after="2024-01-09")输出:

以上这些也都适用于 DataFrame,对其行进行索引,还是代码示例来学习:

import numpy as np
import pandas as pd

np.random.seed(12345)

dates = pd.date_range("2020-01-01", periods=100, freq="W-WED")
long_df = pd.DataFrame(np.random.standard_normal((100, 4)),
                       index=dates,
                       columns=["Colorado", "Texas",
                                "New York", "Ohio"])
print(long_df.loc["2021-05"])

输出结果:

ColoradoTexasNew YorkOhio
2021-05-05-0.115413-0.3507450.044697-0.897756
2021-05-120.890874-1.151185-2.6123031.141250
2021-05-19-0.8671360.383583-0.4370300.347489
2021-05-26-1.2301790.5710780.060061-0.225524

具有重复索引的时间序列(Time Series with Duplicate Indices)

在某些应用程序中,可能会有多个数据观测值落在特定时间戳上。下面是一个代码示例:

import numpy as np
import pandas as pd

np.random.seed(12345)

dates = pd.DatetimeIndex(["2020-01-01", "2020-01-02", "2020-01-02",
                          "2020-01-02", "2020-01-03"])
dup_ts = pd.Series(np.arange(5), index=dates)
print(dup_ts)

# 可以通过检查索引的 is_unique 属性来判断索引不唯一
print(dup_ts.index.is_unique)

# 索引到此时间序列将生成标量值或切片,具体取决于时间戳是否重复:
# 如果用的是没有重复的索引则输出一个标量值
# 如果是有重复的索引则输出的是一个切片
print(dup_ts["2020-01-03"]) # 无重复
print(dup_ts["2020-01-02"]) # 有重复

# 如果要聚合具有非唯一时间戳的数据。
# 一种方法是使用 groupby 并传递 level=0 (唯一的级别)
grouped = dup_ts.groupby(level=0)
print(grouped.mean())
print(grouped.count())

dup_ts输出:

dup_ts.index.is_unique 输出:False

dup_ts["2020-01-03"] 输出:4

dup_ts["2020-01-02"] 输出:

grouped.mean() 输出:

grouped.count() 输出:


http://www.kler.cn/a/399525.html

相关文章:

  • Spring Events在大型项目中的最佳实践
  • 自动化运维(k8s):一键获取指定命名空间镜像包脚本
  • Python绘制雪花
  • Kafka简单实践
  • 【Mysql】Mysql函数(上)
  • 华东师范大学数学分析第五版PDF习题答案上册及下册
  • 炼码LintCode--数据库题库(级别:简单;数量:55道)--刷题笔记_02
  • C++【nlohmann/json】库序列化与反序列化
  • ALSA - (高级Linux声音架构)是什么?
  • ShardingSphere 如何完美驾驭分布式事务与 XA 协议?
  • HTTP常见的状态码有哪些,都代表什么意思
  • DB_redis数据一致性(三)
  • web3+web2安全/前端/钱包/合约测试思路——尝试前端绕过直接上链寻找漏洞
  • @bytemd/vue-next Markdown编辑器的使用
  • Linux下MySQL的简单使用
  • 定时器(QTimer)与随机数生成器(QRandomGenerator)的应用实践——Qt(C++)
  • Linux中的挂载
  • vue 自定义指令( 全局自定义指令 | 局部自定义指令 )
  • 深度学习之GAN的生成能力评价
  • Windows C++ TCP/IP 两台电脑上互相传输字符串数据
  • 【Linux学习】【Ubuntu入门】1-4 ubuntu终端操作与shell命令1
  • 数据驱动的期货市场决策:民锋科技的量化分析创新
  • Python 小高考篇(4)循环语句
  • web——upload-labs——第三关——后缀黑名单绕过
  • main中的int argc, char* argv[],命令行调用函数时输入参数用的
  • Ubuntu24.04LTS在线安装Docker引擎