Python中关于日期和时间、日历数据的模块为datatime、time、calendar
**datatime模块中的数据类型如下:即from datatime import *****
data | 用公历日历存储日历日期(年、月、日) |
---|---|
time | 将时间存储为小时、分钟、秒、微秒 |
datatime | 存储日期和时间 |
timedelta | 表示两个datatime值之间的的差(如日、秒、微秒) |
tzinfo | 用于存储时区信息的基本类型 |
datatime格式化详细说明(兼容ISO C89)
%Y | 四位的年份 |
---|---|
%y | 两位的年份 |
%m | 两位的月份[01, 12] |
%d | 两位的日期号[01, 31] |
%H | 小时,24小时制[00, 23] |
%I | 小时,12小时制[01, 12] |
%M | 两位的分钟[00, 59] |
%s | 秒[00, 61](60,61是闰秒) |
%w | 星期日期[0(星期天), 6] |
%U | 一年中的星期数[00, 53]。以星期天为每周的第一天,一年中第一个星期天前的日期作为‘第0周’ |
%W | 一年中的星期数[00, 53]。以星期一为每周的第一天,一年中第一个星期一前的日期作为‘第0周’ |
%z | 格式为+HHMM或-HHMM的UTC时区偏移;如果没有时区则为空 |
%F | %Y-%m-%d的简写(如,2021-6-24) |
%D | %m/%d/%y的简写(如,06/24/21) |
datatime对象特定地区日期格式化选项
%a | 缩写的工作日名称 |
---|---|
%A | 全写的工作日名称 |
%b | 简写的月份名称 |
%B | 全写的月份名称 |
%c | 完整的日期和时间 (如,‘Tue 01 May 2012 04:20:57 PM’) |
%p | AM或PM的地区等效 |
%x | 适合地区的格式化日期 (如在美国 '05/01/2012’即为May 1) |
%X | 适合地区的时间 (如,’ 04:24:12 PM ') |
import numpy as npimport pandas as pdnp.random.seed(12345)import matplotlib.pyplot as pltplt.rc('figure', figsize=(10, 6))PREVIoUS_MAX_ROWS = pd.options.display.max_rowspd.options.display.max_rows = 20np.set_printoptions(precision=4, suppress=True)
@H_987_301@from datetime import datetimeNow = datetime.Now()Now'''datetime.datetime(2021, 6, 24, 16, 47, 28, 879956)'''Now.year, Now.month, Now.day'''(2021, 6, 24)'''# timedelta表示两个datetime对象的时间差delta = datetime(2011, 1, 7) - datetime(2008, 6, 24, 8, 15)delta'''datetime.timedelta(days=926, seconds=56700)'''delta.days'''926'''delta.seconds'''56700'''# 为datetime对象加/减一个timedelta产生新的datatime对象from datetime import timedeltastart = datetime(2011, 1, 7)start + timedelta(12)'''datetime.datetime(2011, 1, 19, 0, 0)'''start - 2 * timedelta(12)'''datetime.datetime(2010, 12, 14, 0, 0)'''
@H_987_301@字符串与datatime间的转换# 用str方法或传递一个指定格式给strftime方法对datetime对象和pandas的Timestamp对象进行格式化stamp = datetime(2011, 1, 3)str(stamp)''''2011-01-03 00:00:00''''stamp.strftime('%Y-%m-%d')''''2011-01-03''''# 用datetime.strptime()和格式码将字符串转换为日期# datetime.strptime()是在已知格式的情况下转换日期的好方法value = '2011-01-03'datetime.strptime(value, '%Y-%m-%d')'''datetime.datetime(2011, 1, 3, 0, 0)'''datestrs = ['7/6/2011', '8/6/2011'][datetime.strptime(x, '%m/%d/%Y') for x in datestrs]'''[datetime.datetime(2011, 7, 6, 0, 0), datetime.datetime(2011, 8, 6, 0, 0)]'''# 对于通用的日期格式可以使用dateutil包的parser.parse方法# dateutil可以解析大部分人类可理解的日期表示from dateutil.parser import parseparse('2011-01-03')'''datetime.datetime(2011, 1, 3, 0, 0)'''parse('Jan 31, 1997 10:45 PM')'''datetime.datetime(1997, 1, 31, 22, 45)'''# 传递dayfirst=True,来解析日期在月份之前的数据parse('6/12/2011', dayfirst=True)'''datetime.datetime(2011, 12, 6, 0, 0)'''# pd.to_datetime()可以转换很多不同的日期格式datestrs = ['2011-07-06 12:00:00', '2011-08-06 00:00:00']pd.to_datetime(datestrs)'''DatetimeIndex(['2011-07-06 12:00:00', '2011-08-06 00:00:00'], dtype='datetime64[ns]', freq=None)'''# pd.to_datetime()还可处理那些被认为是缺失值的值(None,空字符串等)IDx = pd.to_datetime(datestrs + [None])IDx'''DatetimeIndex(['2011-07-06 12:00:00', '2011-08-06 00:00:00', 'NaT'], dtype='datetime64[ns]', freq=None)'''IDx[2] # NaT(Not a time)是pandas中时间戳数据值是null的值'''NaT'''pd.isnull(IDx)'''array([False, False, True])'''
@H_987_301@二、时间序列基础pandas中的基础时间序列种类是由时间戳索引的SerIEs;
pandas外部则通常表示为python字符串或datatime对象
from datetime import datetimedates = [datetime(2011, 1, 2), datetime(2011, 1, 5), datetime(2011, 1, 7), datetime(2011, 1, 8), datetime(2011, 1, 10), datetime(2011, 1, 12)]# pandas中基础的时间序列:由时间戳索引的SerIEsts = pd.SerIEs(np.random.randn(6), index=dates)ts'''2011-01-02 -0.2047082011-01-05 0.4789432011-01-07 -0.5194392011-01-08 -0.5557302011-01-10 1.9657812011-01-12 1.393406dtype: float64'''# 这些datetime对象实际上是被放在一个DatetimeIndex中ts.index'''DatetimeIndex(['2011-01-02', '2011-01-05', '2011-01-07', '2011-01-08', '2011-01-10', '2011-01-12'], dtype='datetime64[ns]', freq=None)'''
@H_987_301@# 跟其他SerIEs一样,不同索引的时间序列之间的算术运算会自动按日期对齐ts + ts[::2]'''2011-01-02 -0.4094152011-01-05 NaN2011-01-07 -1.0388772011-01-08 NaN2011-01-10 3.9315612011-01-12 NaNdtype: float64'''# pandas用NumPy的datetime64数据类型以纳秒ns形式存储时间戳ts.index.dtype'''dtype('<M8[ns]')'''# DatetimeIndex中的各个标量值是pandas的Timestamp对象stamp = ts.index[0]stamp'''Timestamp('2011-01-02 00:00:00')'''
@H_987_301@索引、选择、子集# 当基于标签进行索引和选择时,时间序列和其他pandas.SerIEs类似stamp = ts.index[2]ts[stamp]'''-0.5194387150567381'''# 传递能解释为日期的字符串,'20110110'也可以ts['1/10/2011']'''1.9657805725027142'''
@H_987_301@# 对于长的时间序列,可以传递一个可解释为年份或年份月份的字符串选择数据longer_ts = pd.SerIEs(np.random.randn(1000), index=pd.date_range('1/1/2000', periods=1000))longer_ts'''2000-01-01 0.0929082000-01-02 0.2817462000-01-03 0.7690232000-01-04 1.2464352000-01-05 1.007189 ... 2002-09-22 0.9309442002-09-23 -0.8116762002-09-24 -1.8301562002-09-25 -0.1387302002-09-26 0.334088Freq: D, Length: 1000, dtype: float64'''longer_ts['2001']'''2001-01-01 1.5995342001-01-02 0.4740712001-01-03 0.1513262001-01-04 -0.5421732001-01-05 -0.475496 ... 2001-12-27 0.0578742001-12-28 -0.4337392001-12-29 0.0926982001-12-30 -1.3978202001-12-31 1.457823Freq: D, Length: 365, dtype: float64'''longer_ts['2001-05']'''2001-05-01 -0.6225472001-05-02 0.9362892001-05-03 0.7500182001-05-04 -0.0567152001-05-05 2.300675 ... 2001-05-27 0.2354772001-05-28 0.1118352001-05-29 -1.2515042001-05-30 -2.9493432001-05-31 0.634634Freq: D, Length: 31, dtype: float64'''
@H_987_301@ts'''2011-01-02 -0.2047082011-01-05 0.4789432011-01-07 -0.5194392011-01-08 -0.5557302011-01-10 1.9657812011-01-12 1.393406dtype: float64'''# 传递datatime对象进行切片ts[datetime(2011, 1, 7):]'''2011-01-07 -0.5194392011-01-08 -0.5557302011-01-10 1.9657812011-01-12 1.393406dtype: float64'''# 传递不包含在时间序列中的时间戳进行切片,以执行范围查询ts['1/6/2011':'1/11/2011']'''2011-01-07 -0.5194392011-01-08 -0.5557302011-01-10 1.965781dtype: float64'''
@H_987_301@传递可别解释为日期的字符串、datatime对象或时间戳进行切片都是产生了原时间序列的视图;即没有数据被复制,且在切片上的修改会反映到原始数据上
# 等价的实例方法truncate,可以在两个日期间对SerIEs进行切片ts.truncate(before='1/5/2011', after='1/10/2011')'''2011-01-05 0.4789432011-01-07 -0.5194392011-01-08 -0.5557302011-01-10 1.965781dtype: float64'''
@H_987_301@# 上面的这些 *** 作也适用于DataFramedates = pd.date_range('1/1/2000', periods=100, freq='W-WED')long_df = pd.DataFrame(np.random.randn(100, 4), index=dates, columns=['colorado', 'Texas', 'New York', 'Ohio'])long_df.loc['5-2001']
@H_987_301@含有重复索引的时间序列# 在某个时间戳上有多个数据观察值,即时间序列含有重复索引dates = pd.DatetimeIndex(['1/1/2000', '1/2/2000', '1/2/2000', '1/2/2000', '1/3/2000'])dup_ts = pd.SerIEs(np.arange(5), index=dates)dup_ts'''2000-01-01 02000-01-02 12000-01-02 22000-01-02 32000-01-03 4dtype: int32'''# 通过index.is_unique属性,查看索引是否唯一dup_ts.index.is_unique'''False'''
@H_987_301@# 对含有重复索引的时间序列进行索引,结果是标量还是SerIEs切片取决于时间戳是否重复dup_ts['1/3/2000'] # not duplicated'''4'''dup_ts['1/2/2000'] # duplicated'''2000-01-02 12000-01-02 22000-01-02 3dtype: int32'''
@H_987_301@# 聚合含有重复索引的数据,传递level=0给groupby即可grouped = dup_ts.groupby(level=0)grouped.mean()'''2000-01-01 02000-01-02 22000-01-03 4dtype: int32'''grouped.count()'''2000-01-01 12000-01-02 32000-01-03 1dtype: int64'''
@H_987_301@三、日期范围、频率和移位生成日期范围# pd.date_range():根据特定频率生成指定长度的DatatimeIndex# 默认生成每日的时间戳index = pd.date_range('2012-04-01', '2012-06-01')index'''DatetimeIndex(['2012-04-01', '2012-04-02', '2012-04-03', '2012-04-04', '2012-04-05', '2012-04-06', '2012-04-07', '2012-04-08', '2012-04-09', '2012-04-10', '2012-04-11', '2012-04-12', '2012-04-13', '2012-04-14', '2012-04-15', '2012-04-16', '2012-04-17', '2012-04-18', '2012-04-19', '2012-04-20', '2012-04-21', '2012-04-22', '2012-04-23', '2012-04-24', '2012-04-25', '2012-04-26', '2012-04-27', '2012-04-28', '2012-04-29', '2012-04-30', '2012-05-01', '2012-05-02', '2012-05-03', '2012-05-04', '2012-05-05', '2012-05-06', '2012-05-07', '2012-05-08', '2012-05-09', '2012-05-10', '2012-05-11', '2012-05-12', '2012-05-13', '2012-05-14', '2012-05-15', '2012-05-16', '2012-05-17', '2012-05-18', '2012-05-19', '2012-05-20', '2012-05-21', '2012-05-22', '2012-05-23', '2012-05-24', '2012-05-25', '2012-05-26', '2012-05-27', '2012-05-28', '2012-05-29', '2012-05-30', '2012-05-31', '2012-06-01'], dtype='datetime64[ns]', freq='D')'''
@H_987_301@# 若只传递一个起始或结尾日期,则必须传递一个用于生成范围的数字给periodspd.date_range(start='2012-04-01', periods=20)'''DatetimeIndex(['2012-04-01', '2012-04-02', '2012-04-03', '2012-04-04', '2012-04-05', '2012-04-06', '2012-04-07', '2012-04-08', '2012-04-09', '2012-04-10', '2012-04-11', '2012-04-12', '2012-04-13', '2012-04-14', '2012-04-15', '2012-04-16', '2012-04-17', '2012-04-18', '2012-04-19', '2012-04-20'], dtype='datetime64[ns]', freq='D')'''pd.date_range(end='2012-06-01', periods=20)'''DatetimeIndex(['2012-05-13', '2012-05-14', '2012-05-15', '2012-05-16', '2012-05-17', '2012-05-18', '2012-05-19', '2012-05-20', '2012-05-21', '2012-05-22', '2012-05-23', '2012-05-24', '2012-05-25', '2012-05-26', '2012-05-27', '2012-05-28', '2012-05-29', '2012-05-30', '2012-05-31', '2012-06-01'], dtype='datetime64[ns]', freq='D')'''
@H_987_301@# 传递时间序列频率给freq,会生成落在指定日期范围的DatatimeIndexpd.date_range('2000-01-01', '2000-12-01', freq='BM')'''DatetimeIndex(['2000-01-31', '2000-02-29', '2000-03-31', '2000-04-28', '2000-05-31', '2000-06-30', '2000-07-31', '2000-08-31', '2000-09-29', '2000-10-31', '2000-11-30'], dtype='datetime64[ns]', freq='BM')'''
@H_987_301@# pd.date_range()默认保留开始或结束时间戳的时间# 传递normalize=True会标准化为零点的时间戳,即去掉了时间戳中的时间pd.date_range('2012-05-02 12:56:31', periods=5)'''DatetimeIndex(['2012-05-02 12:56:31', '2012-05-03 12:56:31', '2012-05-04 12:56:31', '2012-05-05 12:56:31', '2012-05-06 12:56:31'], dtype='datetime64[ns]', freq='D')'''pd.date_range('2012-05-02 12:56:31', periods=5, normalize=True)'''DatetimeIndex(['2012-05-02', '2012-05-03', '2012-05-04', '2012-05-05', '2012-05-06'], dtype='datetime64[ns]', freq='D')'''
@H_987_301@
基础时间序列频率 | ||
---|---|---|
别名 | 偏置类型 | 描述 |
D | Day | 日历日的每天 |
M | BusinessDay | 工作日的每天 |
H | Hour | 每小时 |
T或min | Minute | 每分钟 |
S | Second | 每秒 |
L或ms | Milli | 每毫秒(1/1000秒) |
U | Micro | 每微秒(1/1000000秒) |
M | MonthEnd | 日历的月内最后一天 |
BM | BusinessMonthEnd | 工作日的月内最后一天 |
MS | MonthBegin | 日历的月内第一天 |
BMS | BusinessMonthBegin | 工作日的月内第一天 |
W-MON,W-TUE,…… | Week | 按给定星期日期按每周取日期(MON,TUE,WED,THU,FRI,SAT或SUN) |
WOM-1MON,WOM-2MON,…… | WeekOfMonth | 在本月的一/二/三或四周创建按周分隔的日期(如WOM-3FRI:每月第3个星期五) |
Q-JAN,Q-FEB,…… | QuarterEnd | 每月最后一个日历日的季度日期,以表示月份结束的年份 (JAN,FEB,MAR,APR,MAY,JUN,Jul,AUG,SEP,OCT,NOV或DEC) |
BQ-JAN,BQ-FEB,…… | BusinessQuarterEnd | 每月最后一个工作日对应的季度日期,以表示月份结束的年份 |
QS-JAN,QS-FEB,…… | QuarterBegin | 每月第一个日历日对应的季度日期,以表示月份结束的年份 |
BQS-JAN,BQS-FEB,…… | BusinessQuarterBegin | 每月第一个工作日对应的季度日期,以表示月份结束的年份 |
A-JAN,A-FEB,…… | YearEnd | 给定月份所在月的最后一个日历日的年度日期 (JAN,FEB,MAR,APR,MAY,JUN,Jul,AUG,SEP,OCT,NOV或DEC) |
BA-JAN,BA-FEB,…… | BusinessYearEnd | 给定月份所在月的最后一个工作日的年度日期 |
AS-JAN,AS-FEB,…… | YearBegin | 给定月份所在月的第一个日历日的年度日期 |
BAS-JAN,BAS-FEB,…… | BusinessYearBegin | 给定月份所在月的第一个工作日的年度日期 |
# 对于每个基础频率,都有一个对象可别用于定义日期偏置# 如,每小时的频率可用Hour类来表示from pandas.tserIEs.offsets import Hour, Minutehour = Hour()hour'''<Hour>'''# 传递整数定义偏置量的倍数four_hours = Hour(4)four_hours'''<4 * Hours>'''pd.date_range('2000-01-01', '2000-01-03 23:59', freq='4h')'''DatetimeIndex(['2000-01-01 00:00:00', '2000-01-01 04:00:00', '2000-01-01 08:00:00', '2000-01-01 12:00:00', '2000-01-01 16:00:00', '2000-01-01 20:00:00', '2000-01-02 00:00:00', '2000-01-02 04:00:00', '2000-01-02 08:00:00', '2000-01-02 12:00:00', '2000-01-02 16:00:00', '2000-01-02 20:00:00', '2000-01-03 00:00:00', '2000-01-03 04:00:00', '2000-01-03 08:00:00', '2000-01-03 12:00:00', '2000-01-03 16:00:00', '2000-01-03 20:00:00'], dtype='datetime64[ns]', freq='4H')'''# 多个偏置可通过加法联合Hour(2) + Minute(30)'''<150 * Minutes>'''pd.date_range('2000-01-01', periods=10, freq='1h30min')'''DatetimeIndex(['2000-01-01 00:00:00', '2000-01-01 01:30:00', '2000-01-01 03:00:00', '2000-01-01 04:30:00', '2000-01-01 06:00:00', '2000-01-01 07:30:00', '2000-01-01 09:00:00', '2000-01-01 10:30:00', '2000-01-01 12:00:00', '2000-01-01 13:30:00'], dtype='datetime64[ns]', freq='90T')'''# 传递freq='WOM-3FRI',获取指定日期范围的月中某星期的第三个星期五的日期rng = pd.date_range('2012-01-01', '2012-09-01', freq='WOM-3FRI')List(rng)'''[Timestamp('2012-01-20 00:00:00', freq='WOM-3FRI'), Timestamp('2012-02-17 00:00:00', freq='WOM-3FRI'), Timestamp('2012-03-16 00:00:00', freq='WOM-3FRI'), Timestamp('2012-04-20 00:00:00', freq='WOM-3FRI'), Timestamp('2012-05-18 00:00:00', freq='WOM-3FRI'), Timestamp('2012-06-15 00:00:00', freq='WOM-3FRI'), Timestamp('2012-07-20 00:00:00', freq='WOM-3FRI'), Timestamp('2012-08-17 00:00:00', freq='WOM-3FRI')]'''
@H_987_301@向前或向后移位日期# 移位指将时间序列中数据按时间向前或向后移动# 通过SerIEs或者DataFrame的shift()方法实现ts = pd.SerIEs(np.random.randn(4), index=pd.date_range('1/1/2000', periods=4, freq='M'))ts'''2000-01-31 -0.0667482000-02-29 0.8386392000-03-31 -0.1173882000-04-30 -0.517795Freq: M, dtype: float64'''# 向前移位数据,会在起始位引入缺失值ts.shift(2)'''2000-01-31 NaN2000-02-29 NaN2000-03-31 -0.0667482000-04-30 0.838639Freq: M, dtype: float64'''# 向后移位数据,会在结束为引入缺失值ts.shift(-2)'''2000-01-31 -0.1173882000-02-29 -0.5177952000-03-31 NaN2000-04-30 NaNFreq: M, dtype: float64'''
@H_987_301@shift()常用于计算时间序列或DataFrame多列时间序列的百分比变化,即ts/ts.shift(1)-1
# 传递频率freq='M'给shift将会移位时间戳,而不是数据# 这里表示:时间戳向前移位两个月,即+2个月# 注意数据的向前移位与时间戳的向前移位的差异ts.shift(2, freq='M')'''2000-03-31 -0.0667482000-04-30 0.8386392000-05-31 -0.1173882000-06-30 -0.517795Freq: M, dtype: float64'''# 传递freq='D',表示每个时间戳按天向前移位3天,即+3天ts.shift(3, freq='D')'''2000-02-03 -0.0667482000-03-03 0.8386392000-04-03 -0.1173882000-05-03 -0.517795dtype: float64'''# # 传递freq='90T',表示每个时间戳向前移位90分钟ts.shift(1, freq='90T')'''2000-01-31 01:30:00 -0.0667482000-02-29 01:30:00 0.8386392000-03-31 01:30:00 -0.1173882000-04-30 01:30:00 -0.517795dtype: float64'''
@H_987_301@使用偏置进行移位日期# pandas日期偏置也可使用datatime或Timestamp对象完成from pandas.tserIEs.offsets import Day, MonthEndNow = datetime(2011, 11, 17)Now + 3 * Day()'''Timestamp('2011-11-20 00:00:00')'''# 锚定偏置量,如MonthEnd,BusinessMonthEnd会将日期前滚到下一个日期Now + MonthEnd()'''Timestamp('2011-11-30 00:00:00')'''Now + MonthEnd(2)'''Timestamp('2011-12-31 00:00:00')'''# 锚定偏置可用rollforward,rollback显示的将日期向前或向后滚动offset = MonthEnd()offset.rollforward(Now)'''Timestamp('2011-11-30 00:00:00')'''offset.rollback(Now)'''Timestamp('2011-12-31 00:00:00')'''
@H_987_301@# 将移位方法与groupby一起使用ts = pd.SerIEs(np.random.randn(20), index=pd.date_range('1/15/2000', periods=20, freq='4d'))ts'''2000-01-15 -0.1166962000-01-19 2.3896452000-01-23 -0.9324542000-01-27 -0.2293312000-01-31 -1.1403302000-02-04 0.4399202000-02-08 -0.8237582000-02-12 -0.5209302000-02-16 0.3502822000-02-20 0.2043952000-02-24 0.1334452000-02-28 0.3279052000-03-03 0.0721532000-03-07 0.1316782000-03-11 -1.2974592000-03-15 0.9977472000-03-19 0.8709552000-03-23 -0.9912532000-03-27 0.1516992000-03-31 1.266151Freq: 4D, dtype: float64'''# offset.rollforward会默认对ts的时间戳索引进行 *** 作ts.groupby(offset.rollforward).mean()'''2000-01-31 -0.0058332000-02-29 0.0158942000-03-31 0.150209dtype: float64'''# resample()方法可达到同的效果ts.resample('M').mean()'''2000-01-31 -0.0058332000-02-29 0.0158942000-03-31 0.150209Freq: M, dtype: float64'''
@H_987_301@四、时区处理# 时区通常被表示为UTC的偏置,时区信息来源于第三方库pytzimport pytzpytz.common_timezones[-5:]'''['US/Eastern', 'US/Hawaii', 'US/Mountain', 'US/Pacific', 'UTC']'''# pytz.timezone()获得pytz的时区对象tz = pytz.timezone('America/New_York')tz'''<DstTzInfo 'America/New_York' LMT-1 day, 19:04:00 STD>'''
@H_987_301@时区的本地化和转换rng = pd.date_range('3/9/2012 9:30', periods=6, freq='D')ts = pd.SerIEs(np.random.randn(len(rng)), index=rng)ts'''2012-03-09 09:30:00 -0.2024692012-03-10 09:30:00 0.0507182012-03-11 09:30:00 0.6398692012-03-12 09:30:00 0.5975942012-03-13 09:30:00 -0.7972462012-03-14 09:30:00 0.472879Freq: D, dtype: float64'''# 用于返回时区print(ts.index.tz)'''None'''# 日期范围可通过时区集合生成pd.date_range('3/9/2012 9:30', periods=10, freq='D', tz='UTC')'''DatetimeIndex(['2012-03-09 09:30:00+00:00', '2012-03-10 09:30:00+00:00', '2012-03-11 09:30:00+00:00', '2012-03-12 09:30:00+00:00', '2012-03-13 09:30:00+00:00', '2012-03-14 09:30:00+00:00', '2012-03-15 09:30:00+00:00', '2012-03-16 09:30:00+00:00', '2012-03-17 09:30:00+00:00', '2012-03-18 09:30:00+00:00'], dtype='datetime64[ns, UTC]', freq='D')'''
@H_987_301@ts'''2012-03-09 09:30:00 -0.2024692012-03-10 09:30:00 0.0507182012-03-11 09:30:00 0.6398692012-03-12 09:30:00 0.5975942012-03-13 09:30:00 -0.7972462012-03-14 09:30:00 0.472879Freq: D, dtype: float64'''# 用tz_localize()可将简单时区转化为本地化时区ts_utc = ts.tz_localize('UTC')ts_utc'''2012-03-09 09:30:00+00:00 -0.2024692012-03-10 09:30:00+00:00 0.0507182012-03-11 09:30:00+00:00 0.6398692012-03-12 09:30:00+00:00 0.5975942012-03-13 09:30:00+00:00 -0.7972462012-03-14 09:30:00+00:00 0.472879Freq: D, dtype: float64'''ts_utc.index'''DatetimeIndex(['2012-03-09 09:30:00+00:00', '2012-03-10 09:30:00+00:00', '2012-03-11 09:30:00+00:00', '2012-03-12 09:30:00+00:00', '2012-03-13 09:30:00+00:00', '2012-03-14 09:30:00+00:00'], dtype='datetime64[ns, UTC]', freq='D')'''# 本地化时区可通过tz_convert()转换为另一个时区ts_utc.tz_convert('America/New_York')'''2012-03-09 04:30:00-05:00 -0.2024692012-03-10 04:30:00-05:00 0.0507182012-03-11 05:30:00-04:00 0.6398692012-03-12 05:30:00-04:00 0.5975942012-03-13 05:30:00-04:00 -0.7972462012-03-14 05:30:00-04:00 0.472879Freq: D, dtype: float64'''# 用tz_localize()本地化时区为美国纽约时区ts_eastern = ts.tz_localize('America/New_York')ts_eastern.tz_convert('UTC')'''2012-03-09 14:30:00+00:00 -0.2024692012-03-10 14:30:00+00:00 0.0507182012-03-11 13:30:00+00:00 0.6398692012-03-12 13:30:00+00:00 0.5975942012-03-13 13:30:00+00:00 -0.7972462012-03-14 13:30:00+00:00 0.472879dtype: float64'''ts_eastern.tz_convert('Europe/Berlin')'''2012-03-09 15:30:00+01:00 -0.2024692012-03-10 15:30:00+01:00 0.0507182012-03-11 14:30:00+01:00 0.6398692012-03-12 14:30:00+01:00 0.5975942012-03-13 14:30:00+01:00 -0.7972462012-03-14 14:30:00+01:00 0.472879dtype: float64'''# tz_localize()、tz_convert()也是DatetimeIndex的实例方法ts.index.tz_localize('Asia/Shanghai')'''DatetimeIndex(['2012-03-09 09:30:00+08:00', '2012-03-10 09:30:00+08:00', '2012-03-11 09:30:00+08:00', '2012-03-12 09:30:00+08:00', '2012-03-13 09:30:00+08:00', '2012-03-14 09:30:00+08:00'], dtype='datetime64[ns, Asia/Shanghai]', freq=None)'''
@H_987_301@时区感知时间戳对象的 *** 作# 单独的Timestamp对象也可本地化为时区感知时间戳,并进行时区转化stamp = pd.Timestamp('2011-03-12 04:00')stamp_utc = stamp.tz_localize('utc')stamp_utc.tz_convert('America/New_York')'''Timestamp('2011-03-11 23:00:00-0500', tz='America/New_York')'''# 创建Timestamp对象时传递时区stamp_moscow = pd.Timestamp('2011-03-12 04:00', tz='Europe/Moscow')stamp_moscow'''Timestamp('2011-03-12 04:00:00+0300', tz='Europe/Moscow')'''# 时区感知的Timestamp对象内存储了一个Unix纪元(1970-1-1)至今的纳秒数量的UTC时间戳数值stamp_utc.value'''1299902400000000000'''# 纳秒数量UTC时间戳数值在时区转化中不变stamp_utc.tz_convert('America/New_York').value'''1299902400000000000'''
@H_987_301@from pandas.tserIEs.offsets import Hourstamp = pd.Timestamp('2012-03-12 01:30', tz='US/Eastern')stamp'''Timestamp('2012-03-12 01:30:00-0400', tz='US/Eastern')'''# 加的Hour()是UTC的1小时stamp + Hour()'''Timestamp('2012-03-12 02:30:00-0400', tz='US/Eastern')'''stamp = pd.Timestamp('2012-11-04 00:30', tz='US/Eastern')stamp'''Timestamp('2012-11-04 00:30:00-0400', tz='US/Eastern')'''stamp + 2 * Hour()'''Timestamp('2012-11-04 01:30:00-0500', tz='US/Eastern')'''
@H_987_301@不同时区间的 *** 作# 不同时区间的 *** 作会先自动转为UTC时间,结果也是UTC时间rng = pd.date_range('3/7/2012 9:30', periods=10, freq='B')ts = pd.SerIEs(np.random.randn(len(rng)), index=rng)ts'''2012-03-07 09:30:00 0.5223562012-03-08 09:30:00 -0.5463482012-03-09 09:30:00 -0.7335372012-03-12 09:30:00 1.3027362012-03-13 09:30:00 0.0221992012-03-14 09:30:00 0.3642872012-03-15 09:30:00 -0.9228392012-03-16 09:30:00 0.3126562012-03-19 09:30:00 -1.1284972012-03-20 09:30:00 -0.333488Freq: B, dtype: float64'''ts1 = ts[:7].tz_localize('Europe/London')ts2 = ts1[2:].tz_convert('Europe/Moscow')result = ts1 + ts2result.index'''DatetimeIndex(['2012-03-07 09:30:00+00:00', '2012-03-08 09:30:00+00:00', '2012-03-09 09:30:00+00:00', '2012-03-12 09:30:00+00:00', '2012-03-13 09:30:00+00:00', '2012-03-14 09:30:00+00:00', '2012-03-15 09:30:00+00:00'], dtype='datetime64[ns, UTC]', freq=None)'''
@H_987_301@五、时间区间和区间算术Period类表示的是时间区间,即时间范围。如,一些天、一些月、一些季度、一些年
# 以下Period对象表示从2007年1月1日到2007年12月31日p = pd.Period(2007, freq='A-DEC')p'''Period('2007', 'A-DEC')'''# 做加减法时直接按频率freq='A-DEC'移位p + 5'''Period('2012', 'A-DEC')'''p - 2'''Period('2005', 'A-DEC')'''# 具有相同频率的两个区间的差是频率的倍数pd.Period('2014', freq='A-DEC') - p'''<7 * YearEnds: month=12>'''
@H_987_301@# 用pd.period_range()可构造规则区间序列rng = pd.period_range('2000-01-01', '2000-06-30', freq='M')rng'''Periodindex(['2000-01', '2000-02', '2000-03', '2000-04', '2000-05', '2000-06'], dtype='period[M]', freq='M')'''# Periodindex类存储的是区间序列,可作为pandas数据结构的轴索引pd.SerIEs(np.random.randn(6), index=rng)'''2000-01 -0.5145512000-02 -0.5597822000-03 -0.7834082000-04 -1.7976852000-05 -0.1726702000-06 0.680215Freq: M, dtype: float64'''
@H_987_301@# pd.Periodindex()可生成Periodindex类values = ['2001Q3', '2002Q2', '2003Q1']index = pd.Periodindex(values, freq='Q-DEC')index'''Periodindex(['2001Q3', '2002Q2', '2003Q1'], dtype='period[Q-DEC]', freq='Q-DEC')'''
@H_987_301@区间频率转换# 创建一个Period区间,以12月作为年度结束月份p = pd.Period('2007', freq='A-DEC')p'''Period('2007', 'A-DEC')'''# asfreq()可以将区间和Periodindex对象转换为其他的频率p.asfreq('M', how='start')'''Period('2007-01', 'M')'''p.asfreq('M', how='end')'''Period('2007-12', 'M')'''
@H_987_301@# 创建一个Period区间,以6月作为年度结束月份# 这种情况下,2006年7月至2007年6月作为2007年度p = pd.Period('2007', freq='A-JUN')p'''Period('2007', 'A-JUN')'''# 指定how为'start',会返回2007年度的第一个月# 由于是以6月作为年度的结束月份,故第一个月份为2006-07p.asfreq('M', 'start')'''Period('2006-07', 'M')'''p.asfreq('M', 'end')'''Period('2007-06', 'M')'''
@H_987_301@# 以上是从低频率转换为高频率,也可从高频率转换为低频率,即类似月转为年p = pd.Period('Aug-2007', 'M')p.asfreq('A-JUN')# 传入'A-JUN',表名年度结束月份为6月,故2007-8属于2008年度'''Period('2008', 'A-JUN')'''p = pd.Period('Aug-2007', 'M')p.asfreq('A-SEP')# 传入'A-SEP',表名年度结束月份为6月,故2007-8属于2007年度'''Period('2007', 'A-SEP')'''
@H_987_301@# 完整的Periodindex对象或时间序列均可做以上类似的转换rng = pd.period_range('2006', '2009', freq='A-DEC')ts = pd.SerIEs(np.random.randn(len(rng)), index=rng)ts'''2006 1.6075782007 0.2003812008 -0.8340682009 -0.302988Freq: A-DEC, dtype: float64'''ts.asfreq('M', how='start')'''2006-01 1.6075782007-01 0.2003812008-01 -0.8340682009-01 -0.302988Freq: M, dtype: float64'''ts.asfreq('B', how='end')'''2006-12-29 1.6075782007-12-31 0.2003812008-12-31 -0.8340682009-12-31 -0.302988Freq: B, dtype: float64'''
@H_987_301@季度区间频率# 季度数据一般是财年结尾,故类似2012Q4一般有不同的含义# 设置freq='Q-JAN',表示季度结尾的月份是1月# 故2012Q4表示的是2011年11月到2012年1月这4个月p = pd.Period('2012Q4', freq='Q-JAN')p'''Period('2012Q4', 'Q-JAN')'''p.asfreq('D', 'start')'''Period('2011-11-01', 'D')'''p.asfreq('D', 'end')'''Period('2012-01-31', 'D')'''# 获取季度倒数第2个工作日下午4点的时间戳# p.asfreq('B', 'e') - 1获取季度倒数第2个工作# (p.asfreq('B', 'e') - 1).asfreq('T', 's')将获取的日期转换为分钟,且是当天零点# 再'+ 16 * 60'是加下午4点的分钟数p4pm = (p.asfreq('B', 'e') - 1).asfreq('T', 's') + 16 * 60p4pm'''Period('2012-01-30 16:00', 'T')'''# 用to_timestamp()转换为时间戳p4pm.to_timestamp()'''Timestamp('2012-01-30 16:00:00')'''
@H_987_301@# pd.period_range()用于生成季度序列rng = pd.period_range('2011Q3', '2012Q4', freq='Q-JAN')ts = pd.SerIEs(np.arange(len(rng)), index=rng)ts'''2011Q3 02011Q4 12012Q1 22012Q2 32012Q3 42012Q4 5Freq: Q-JAN, dtype: int32'''# 获取季度倒数第2个工作日下午4点的时间戳new_rng = (rng.asfreq('B', 'e') - 1).asfreq('T', 's') + 16 * 60ts.index = new_rng.to_timestamp()ts'''2010-10-28 16:00:00 02011-01-28 16:00:00 12011-04-28 16:00:00 22011-07-28 16:00:00 32011-10-28 16:00:00 42012-01-30 16:00:00 5dtype: int32'''
@H_987_301@将时间戳转换为区间(及逆转换)rng = pd.date_range('2000-01-01', periods=3, freq='M')ts = pd.SerIEs(np.random.randn(3), index=rng)ts'''2000-01-31 1.6632612000-02-29 -0.9962062000-03-31 1.521760Freq: M, dtype: float64'''# 通过时间戳索引的SerIEs和DataFrame可用to_period()方法转换为区间pts = ts.to_period()pts'''2000-01 1.6632612000-02 -0.9962062000-03 1.521760Freq: M, dtype: float64'''
@H_987_301@rng = pd.date_range('1/29/2000', periods=6, freq='D')ts2 = pd.SerIEs(np.random.randn(6), index=rng)ts2'''2000-01-29 0.2441752000-01-30 0.4233312000-01-31 -0.6540402000-02-01 2.0891542000-02-02 -0.0602202000-02-03 -0.167933Freq: D, dtype: float64'''# 区间转换后索引包含重复区间是被允许的ts2.to_period('M')'''2000-01 0.2441752000-01 0.4233312000-01 -0.6540402000-02 2.0891542000-02 -0.0602202000-02 -0.167933Freq: M, dtype: float64'''
@H_987_301@# 创建以JAN-1月作为每年最后一个季度末的月份rng = pd.period_range('2011Q3', '2012Q4', freq='Q-JAN')ts3 = pd.SerIEs(np.arange(len(rng)), index=rng)ts3'''2011Q3 02011Q4 12012Q1 22012Q2 32012Q3 42012Q4 5Freq: Q-JAN, dtype: int32'''# to_timestamp()可将区间再转换为时间戳# how默认为start,取季度第一个月零点作为索引;也可设置how='end'ts3.to_timestamp()'''2010-08-01 02010-11-01 12011-02-01 22011-05-01 32011-08-01 42011-11-01 5Freq: QS-NOV, dtype: int32'''
@H_987_301@从数组生成Periodindexdata = pd.read_csv('examples/macrodata.csv')data.head(5)
@H_987_301@data.year.head()'''0 1959.01 1959.02 1959.03 1959.04 1960.0name: year, dtype: float64'''data.quarter.head()'''0 1.01 2.02 3.03 4.04 1.0name: quarter, dtype: float64'''index = pd.Periodindex(year=data.year, quarter=data.quarter, freq='Q-DEC')index'''Periodindex(['1959Q1', '1959Q2', '1959Q3', '1959Q4', '1960Q1', '1960Q2', '1960Q3', '1960Q4', '1961Q1', '1961Q2', ... '2007Q2', '2007Q3', '2007Q4', '2008Q1', '2008Q2', '2008Q3', '2008Q4', '2009Q1', '2009Q2', '2009Q3'], dtype='period[Q-DEC]', length=203, freq='Q-DEC')'''data.index = indexdata.head()
@H_987_301@六、重新采样与频率转换重新采样 :将时间序列从一个频率转换为另一个频率的过程
向下采样:将更高频率聚合到低频率
向上采样:将低频率转换到高频率
但并非所有的重新采样都是上面两类,如将W-WED转换到W-REI
pandas对象的resample()方法会进行频率转换,其有类似groupby的功能
rng = pd.date_range('2000-01-01', periods=100, freq='D')ts = pd.SerIEs(np.random.randn(len(rng)), index=rng)ts'''2000-01-01 0.6316342000-01-02 -1.5943132000-01-03 -1.5199372000-01-04 1.1087522000-01-05 1.255853 ... 2000-04-05 -0.4237762000-04-06 0.7897402000-04-07 0.9375682000-04-08 -2.2532942000-04-09 -1.772919Freq: D, Length: 100, dtype: float64'''ts.resample('M').mean()'''2000-01-31 -0.1658932000-02-29 0.0786062000-03-31 0.2238112000-04-30 -0.063643Freq: M, dtype: float64'''# kind='period'指定结果中索引的类型为periodts.resample('M', kind='period').mean()'''2000-01 -0.1658932000-02 0.0786062000-03 0.2238112000-04 -0.063643Freq: M, dtype: float64'''
@H_987_301@
resample()方法的参数 | |
---|---|
freq | 采样频率,为字符串或DataOffset对象(如,‘5min’,‘M’,或Second(1)) |
axis | 沿着哪个轴采样,默认axis=0 |
fill_method | 向上采样时的差值方式,默认不插值,可选’ffill’、‘bfill’ |
closed | 向下采样中,每段间隔的哪一段是封闭的,可选’right’、‘left’ |
label | 向下采样中,用’right’/'left’的箱标签标记聚合结果(如,9:30到9:35的5分钟间隔可被标记为9:30/9:35) |
loffset | 对箱标签进行时间调校(如,’-1s’/Second(-1)可将聚合标签向前移动1秒) |
limit | 在前向或后向填充时,填充区间最大值 |
kind | 指定结果中索引为区间(‘period’)或时间戳(‘timestamp’),默认为时间序列索引 |
convention | 对区间重新采样时,用于将低频周期转换为高频的约定,默认为’start’,可选’end’ |
使用resample()向下采样需要考虑的事情:
每段间隔的哪一边是闭合的如何在间隔的起始或结束位置标记每个已聚合的箱体rng = pd.date_range('2000-01-01', periods=12, freq='T')ts = pd.SerIEs(np.arange(12), index=rng)ts'''2000-01-01 00:00:00 02000-01-01 00:01:00 12000-01-01 00:02:00 22000-01-01 00:03:00 32000-01-01 00:04:00 42000-01-01 00:05:00 52000-01-01 00:06:00 62000-01-01 00:07:00 72000-01-01 00:08:00 82000-01-01 00:09:00 92000-01-01 00:10:00 102000-01-01 00:11:00 11Freq: T, dtype: int32'''# 默认closed='left',将索引间隔分为[00:00,00:05)、[00:05,00:10)...,# 之后再在这样的间隔上将数据聚合# 默认label='left',在结果中取索引间隔的左侧作为行标签ts.resample('5min', closed='left').sum()'''2000-01-01 00:00:00 102000-01-01 00:05:00 352000-01-01 00:10:00 21Freq: 5T, dtype: int32'''ts.resample('5min', closed='right').sum()'''1999-12-31 23:55:00 02000-01-01 00:00:00 152000-01-01 00:05:00 402000-01-01 00:10:00 11Freq: 5T, dtype: int32'''ts.resample('5min', closed='right', label='right').sum()'''2000-01-01 00:00:00 02000-01-01 00:05:00 152000-01-01 00:10:00 402000-01-01 00:15:00 11Freq: 5T, dtype: int32'''# 设置loffset='1s',会将结果中的索引向右移动1秒,即加1秒ts.resample('5min', closed='right', label='right', loffset='1s').sum()'''2000-01-01 00:00:01 02000-01-01 00:05:01 152000-01-01 00:10:01 402000-01-01 00:15:01 11Freq: 5T, dtype: int32'''
@H_987_301@开端-峰值-谷值-结束(OHLC)重新采样# ohlc()会获得索引间隔内的第一个值、最后一个值、最大值、最小值ts.resample('5min').ohlc()
@H_987_301@向上采样与差值# upsampling时并不需要聚合,用asfreq()进行频率转换frame = pd.DataFrame(np.random.randn(2, 4), index=pd.date_range('1/1/2000', periods=2, freq='W-WED'), columns=['colorado', 'Texas', 'New York', 'Ohio'])frame
@H_987_301@# 用asfreq()进行频率转换,从低频向高频转换时会引入缺失值df_daily = frame.resample('D').asfreq()df_daily
@H_987_301@# 若不想引入缺失值,则可用ffill()设置填充值frame.resample('D').ffill()
@H_987_301@# 传递limit=2给ffill()则仅向前填充两行数据frame.resample('D').ffill(limit=2)
@H_987_301@frame.resample('W-THU').ffill()
@H_987_301@使用区间进行重新采样 resampling with Periodsframe = pd.DataFrame(np.random.randn(24, 4), index=pd.period_range('1-2000', '12-2001', freq='M'), columns=['colorado', 'Texas', 'New York', 'Ohio'])frame[:5]
@H_987_301@# 向下采样,频率为'A-DEC',年度,12月作为年底最后一月annual_frame = frame.resample('A-DEC').mean()annual_frame
@H_987_301@# 向上采样,并设置填充方式ffill(),默认convention='start'# Q-DEC: 季度, 12月作为最后一季度的最后一个月annual_frame.resample('Q-DEC').ffill()
@H_987_301@# 向上采样,设置填充方式ffill()# 传递convention='end',设置结果中索引为原来第一个索引年份的季度末开始,到原来最后一个索引年份的季度末终止annual_frame.resample('Q-DEC', convention='end').ffill()
@H_987_301@向下采样中,原序列中频率必须是结果中频率的子区间;月----年
向上采样总,原序列中频率必须是结果中频率的父区间;年----月
仔细揣摩以下的几种 *** 作,通过画图理解annual_frame.resample('Q-MAR').ffill()
@H_987_301@annual_frame.resample('Q-MAR', convention='end').ffill()
@H_987_301@annual_frame.resample('Q-APR').ffill()
@H_987_301@annual_frame.resample('Q-APR', convention='end').ffill()
@H_987_301@七、移动窗口函数移动窗口函数与其他的统计函数一样,都会自动排除缺失数据
close_px_all = pd.read_csv('examples/stock_px_2.csv', parse_dates=True, index_col=0)close_px = close_px_all[['AAPL', 'MSFT', 'XOM']]close_px
@H_987_301@# 按照工作日频率进行重采样close_px = close_px.resample('B').ffill()close_px
@H_987_301@%matplotlib inlineclose_px.AAPL.plot()# rolling(),可以在SerIEs和DataFrame上通过一个window(即下方传入的数字250)进行调用# 这里是根据250个滑动窗口分组close_px.AAPL.rolling(250).mean().plot()
@H_987_301@# 传递min_periods=10,会最小先计算前10闭的标准差,再计算前11笔的标准差,以此类推# 直到计算到前250组数据后,再采用移动窗口求标准差appl_std250 = close_px.AAPL.rolling(250, min_periods=10).std()appl_std250[5:12]'''2003-01-09 NaN2003-01-10 NaN2003-01-13 NaN2003-01-14 NaN2003-01-15 0.0774962003-01-16 0.0747602003-01-17 0.112368Freq: B, name: AAPL, dtype: float64'''appl_std250.plot()
@H_987_301@# expanding()会使视窗逐渐扩大,左边不动,右边向右扩展;求扩展窗口的均值# 如,这里2003-01-16为原01-16和01-15的均值# 如,这里2003-01-17为原01-15至01-17的均值expanding_mean = appl_std250.expanding().mean()expanding_mean[5:12]'''2003-01-09 NaN2003-01-10 NaN2003-01-13 NaN2003-01-14 NaN2003-01-15 0.0774962003-01-16 0.0761282003-01-17 0.088208Freq: B, name: AAPL, dtype: float64'''# 传递logy=True,对y取对数close_px.rolling(60).mean().plot(logy=True)
@H_987_301@# 传递'20D',固定取日历日的20天进行移动;前面传递250是取索引列的250天作为一个窗口close_px.rolling('20D').mean().head()
@H_987_301@# 传递'3D',固定取日历日的3天进行移动平均# 故结果中2003-01-06的均值不变,因为4和5号没有数据close_px.rolling('3D').mean().head()
@H_987_301@指数加权函数# 通过span=30指定衰减因子,即权重分别为2/31、2/31*29/31.....aapl_px = close_px.AAPL['2006':'2007']# 简单移动平均ma60 = aapl_px.rolling(30, min_periods=20).mean()# 指数加权平均ewma60 = aapl_px.ewm(span=30).mean()ma60.plot(style='k--', label='Simple MA')ewma60.plot(style='k-', label='EW MA')plt.legend()
@H_987_301@二元移动窗口函数同时 *** 作两个时间序列,使用相同的移动窗口大小,如corr()或协方差
spx_px = close_px_all['SPX']spx_rets = spx_px.pct_change()spx_rets'''2003-01-02 NaN2003-01-03 -0.0004842003-01-06 0.0224742003-01-07 -0.0065452003-01-08 -0.014086 ... 2011-10-10 0.0341252011-10-11 0.0005442011-10-12 0.0097952011-10-13 -0.0029742011-10-14 0.017380name: SPX, Length: 2214, dtype: float64'''returns = close_px.pct_change()returns
@H_987_301@# 注意这里,returns.AAPL有2292行数据,而spx_rets有2214行数据# 故他们的行索引在计算移动视窗时并不是完全一样的# 正常情况下,是不会出现这样的情况,可能是作者弄错了# corr()计算滚动相关系数corr = returns.AAPL.rolling(125, min_periods=100).corr(spx_rets)corr.plot()
@H_987_301@corr = returns.rolling(125, min_periods=100).corr(spx_rets)corr.plot()
@H_987_301@用户自定义移动窗口函数# 在rolling()及相关方法上使用apply()可以在移动窗口中使用自定义的数组函数from scipy.stats import percentileofscore# 有多少百分比的样本x小于0.02score_at_2percent = lambda x: percentileofscore(x, 0.02)result = returns.AAPL.rolling(250).apply(score_at_2percent)result.plot()
@H_987_301@ 总结以上是内存溢出为你收集整理的《利用python进行数据分析》第二版 第11章-时间序列 学习笔记全部内容,希望文章能够帮你解决《利用python进行数据分析》第二版 第11章-时间序列 学习笔记所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)