在使用Python进行数据分析时,经常会遇到时间日期格式处理和转换,特别是分析和挖掘与时间相关的数据,比如量化交易就是从历史数据中寻找股价的变化规律。Python中自带的处理时间的模块有datetime,NumPy库也提供了相应的方法,Pandas作为Python环境下的数据分析库,更是提供了强大的日期数据处理的功能,是处理时间序列的利器。
时间序列(time series)数据是一种重要的结构化数据形式。在多个时间点观察或测量到的任何时间都可以形成一段时间序列。很多时间, 时间序列是固定频率的, 也就是说, 数据点是根据某种规律定期出现的(比如每15秒。。。。)。时间序列也可以是不定期的。时间序列数据的意义取决于具体的应用场景。主要有以下几种:
1.时间戳;(timestamp)特定的时刻
2.固定时间:(period)如2010年全年或者某个月份
3.时间间隔:(interval)由起始和结束时间戳表示, 时期(period)可以被看做是间隔(interval)的特例
一、生成时间序列
pd.data_range(start = None, end = None, period = None, freq = 'D')
- start和end以及freq配合能够生成start和end范围以内以频率freq的一组时间索引
- start和periods以及freq配合生成从start开始的频率为freq的periods个时间索引
import pandas as pd
dr = pd.date_range(start='20170215', end='20170430', freq='10D')
print(dr)
dr2 = pd.date_range(start='20170215', periods=10, freq='M')
print(dr2)
关于频率freq的更多缩写:
二、转换时间戳(DatetimeIndex)
你可能会想到,我们经常要和文本数据(字符串)打交道,能否快速将文本数据转为时间戳呢?
答案是可以的,通过 to_datetime 能快速将字符串转换为时间戳。当传递一个Series时,它会返回一个Series(具有相同的索引),而类似列表的则转换为DatetimeIndex。
- dr = pd.to_datetime(Series,format = "")
- format用于指定时间字符串的转换类型,format参数大部分情况下是可以不用写的,但是对于pandas无法格式化的时间字符串,我们可以使用该参数,比如包含中文的
python中时间日期格式化符号:
- %y 两位数的年份表示(00-99)
- %Y 四位数的年份表示(000-9999)
- %m 月份(01-12)
- %d 月内中的一天(0-31)
- %H 24小时制小时数(0-23)
- %I 12小时制小时数(01-12)
- %M 分钟数(00=59)
- %S 秒(00-59)
- %a 本地简化星期名称
- %A 本地完整星期名称
- %b 本地简化的月份名称
- %B 本地完整的月份名称
- %c 本地相应的日期表示和时间表示
- %j 年内的一天(001-366)
- %p 本地A.M.或P.M.的等价符
- %U 一年中的星期数(00-53)星期天为星期的开始
- %w 星期(0-6),星期天为星期的开始
- %W 一年中的星期数(00-53)星期一为星期的开始
- %x 本地相应的日期表示
- %X 本地相应的时间表示
- %Z 当前时区的名称
- %% %号本身
import pandas as pd
dr = pd.to_datetime(pd.Series(["Jul 31, 2018", "2018-05-10", None]))
print(dr)
dr2 = pd.to_datetime(['2020/5/20', '2020/7/20'])
print(dr2)
#除了可以将文本数据转为时间戳外,还可以将 unix 时间转为时间戳
dr3 = pd.to_datetime([1349720105, 1349806505, 1349720105300], unit='ms')
print(dr3)
三、pandas时间段(PeriodIndex)
Pandas 周期索引(PeriodIndex)是针对周期数据的专门索引,可以快速对周期数据进行分析。
periods = pd.PeriodIndex(year=data['year'],month=data['month'],day=data['day'],hour=data[''hour],freq='H')
四、pandas重采样
重采样:指的是将时间序列从一个频率转换为另一个频率进行处理的过程,将高频率数据转换成低频率数据为降采样,低频率转换成高频率为升采样。
注:实际中,采用比较多的是降采样。
pandas提供了一个 resample 方法来帮助我们实现频率转换。
resample方法的参数:
参数 | 说明 |
---|---|
freq | 表示重采样频率,例如‘M’、‘5min’,Second(15) |
how=’mean’ | 用于产生聚合值的函数名或数组函数,例如‘mean’、‘ohlc’、np.max等,默认是‘mean’,其他常用的值由:‘first’、‘last’、‘median’、‘max’、‘min’ |
axis=0 | 默认是纵轴,横轴设置axis=1 |
fill_method = None | 升采样时如何插值,比如‘ffill’、‘bfill’等 |
closed = ‘right’ | 在降采样时,各时间段的哪一段是闭合的,‘right’或‘left’,默认‘right’ |
label= ‘right’ | 在降采样时,如何设置聚合值的标签,例如,9:30-9:35会被标记成9:30还是9:35,默认9:35 |
loffset = None | 面元标签的时间校正值,比如‘-1s’或Second(-1)用于将聚合标签调早1秒 |
limit=None | 在向前或向后填充时,允许填充的最大时期数 |
kind = None | 聚合到时期(‘period’)或时间戳(‘timestamp’),默认聚合到时间序列的索引类型 |
convention = None | 当重采样时期时,将低频率转换到高频率所采用的约定(start或end)。默认‘end’ |
五、紧急电话案例
现在我们有2015到2017年的25万条911的紧急电话的数据,请统计出不同月份不同类型紧急电话的次数的变化情况
- 统计出911数据中不同月份电话次数的变化情况
- 统计出911数据中不同月份不同类型的电话的次数的变化情况
数据来源:https://www.kaggle.com/mchirico/montcoalert/data
注:Python time strftime() 函数接收以时间元组,并返回以可读字符串表示的当地时间,格式由参数 format 决定。
1、统计出911数据中不同月份电话次数的变化情况
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
def myPD():
file_path = "E:/python/pyData/911.csv"
df = pd.read_csv(file_path)
df["timeStamp"] = pd.to_datetime(df["timeStamp"])
df.set_index("timeStamp", inplace=True)
#统计出911数据中不同月份电话次数
count_by_month = df.resample("M").count()["title"]
print(count_by_month)
#绘图
_x = count_by_month.index
_y = count_by_month.values
_x = [i.strftime("%Y%m%d") for i in _x]
plt.figure(figsize=(20,8), dpi=80)
plt.plot(range(len(_x)), _y)
plt.xticks(range(len(_x)), _x, rotation=45)
plt.show()
if __name__ == '__main__':
myPD()
2、统计出911数据中不同月份不同类型的电话的次数的变化情况
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
def myPD():
file_path = "E:/python/pyData/911.csv"
df = pd.read_csv(file_path)
#把时间字符串转换为时间类型
df["timeStamp"] = pd.to_datetime(df["timeStamp"])
#添加列,表示分类
temp_list = df["title"].str.split(": ").tolist()
cate_list = [i[0] for i in temp_list]
df["cate"] = pd.DataFrame(np.array(cate_list).reshape(df.shape[0], 1))
#设置索引
df.set_index("timeStamp", inplace=True)
plt.figure(figsize=(20, 8), dpi=80)
#按照cate进行分组, group_name:分组名 group_data:分组内详细信息
for group_name,group_data in df.groupby(by="cate"):
#对不同分类都进行绘图
count_by_month = group_data.resample("M").count()["title"]
# 绘图
_x = count_by_month.index
_y = count_by_month.values
_x = [i.strftime("%Y%m%d") for i in _x]
plt.plot(range(len(_x)), _y, label=group_name)
plt.xticks(range(len(_x)), _x, rotation=45)
plt.legend(loc="best")
plt.show()
if __name__ == '__main__':
myPD()
六、PM2.5质量检测案例
现在我们有北上广深及沈阳5个城市空气质量数据,请绘制出5个城市的PM2.5随时间变化的情况
数据来源:https://www.kaggle.com/uciml/pm25-data-for-five-chinese-cities
1、日期处理
思路:把分开的时间字符串通过 PeriodIndex 的方法转换成pandas的时间类型
periods = pd.PeriodIndex(year=df['year'], month=df['month'], day=df['day'],hour=df['hour'], freq='H')
print(periods)
print(type(periods))
2、统计不同区域统计出的空气质量情况
import pandas as pd
from matplotlib import pyplot as plt
def myDeal():
file_path = "E:/python/pyData/pm25/BeijingPM20100101_20151231.csv"
df = pd.read_csv(file_path)
print(df.info())
#处理日期,并在原数据中新加入一列,用来存储转换成的时间字串
df["datetime"] = pd.PeriodIndex(year=df['year'], month=df['month'], day=df['day'],hour=df['hour'], freq='H')
print(df.head(10))
#把datatime设置为索引
df.set_index("datetime", inplace=True)
#降采样
df = df.resample("7D").mean()
#处理缺失数据,删除缺失数据
data = df["PM_US Post"].dropna()
#绘图
plt.figure(figsize=(20,8), dpi=80)
_x = data.index
_y = data.values
plt.plot(range(len(_x)), _y)
plt.xticks(range(0,len(_x),20),list(_x)[::20], rotation=45)
plt.show()
if __name__ == '__main__':
myDeal()