《利用Python 进行数据分析》第十章:时间序列_as919488-程序员宅基地

技术标签: 数据分析  

       对《利用Python 进行数据分析》(Wes Mckinney著)一书中的第十章中时间序列进行代码实验。原书中采用的是Python2.7,而我采用的Python3.7在Pycharm调试的,因此对书中源代码进行了一定的修改,每步结果与原文校验对照一致(除了随机函数外;输出结果在注释中,简单的输出就没写结果),全手工敲写,供参考。

       Pdf文档和数据集参见:《利用Python 进行数据分析》第二章:引言中的分析代码(含pdf和数据集下载链接)


       因为代码过长,放在一个代码段中显得冗长,因此进行了拆分,如下的库引入每个代码段中均可能有必要。

# -*- coding:utf-8 -*-
from datetime import datetime, timedelta
import pandas as pd
import numpy as np
from pandas import DataFrame, Series

1、日期和时间数据类型及工具

时间序列数据的意义取决于具体的应用场景
时间戳(timestamp):特定的时刻
固定时期(period):如2007年1月或2010年全年
时间间隔(interval):由起始和结束时间戳表示,时期(period)可以被看作间隔的特例

1.1 日期类型初识

# 主要用到datetime、time以及calendar模块
now = datetime.now()
print(now) # 2020-09-28 14:05:42.871960
print(now.year, now.month, now.day)  # 2020 9 28

# datetime以毫秒形式储存日期和时间
delta = datetime(2011,1,7) - datetime(2008, 6, 24, 8, 15)
print(delta) # 926 days, 15:45:00

# datetime.timedelta表示两个datetime对象之间的时间差
timedelta(926, 56700)
print(delta.days) # 926
print(delta.seconds) # 56700

# 可以给datetime对象加上(减去)一个或多个timedelta,会产生一个新对象
start = datetime(2011,1,7)
ret = start + timedelta(12)
print(ret) # 2011-01-19 00:00:00

ret = start - 2 * timedelta(12)
print(ret) # 2010-12-14 00:00:00

1.2 字符串和datetime相互转换

# 利用str或strftime方法(传入格式化字符串),datetime对象和pandas的Timestamp对象可以被格式化为字符串
stamp = datetime(2011, 1, 3)
print(str(stamp))  # 2011-01-03 00:00:00
print(stamp.strftime('%Y-%m-%d'))  # 2011-01-03

# date.time.strptime也可以用这些格式化编码将字符串转化为日期
value = '2011-01-09'
print(datetime.strptime(value,'%Y-%m-%d')) # 2011-01-09 00:00:00

datestrs=['7/6/2011', '8/6/2011']
print([datetime.strptime(x, '%m/%d/%Y') for x in datestrs])
'''[datetime.datetime(2011, 7, 6, 0, 0), datetime.datetime(2011, 8, 6, 0, 0)]'''

# datetime.strptime是通过已知格式进行日期解析,但每次编写都需要定义格式比较麻烦
# 所以我们可以使用dateutil 这个第三方库的parser.parse方法
from dateutil.parser import parse
print(parse('2011-01-03')) # 2011-01-03 00:00:00

# dateutil 可以解析几乎所有人类能理解的日期表现形式
print(parse('Jan 31, 1997 10:45 PM')) # 1997-01-31 22:45:00

# 国际通用格式中,日常常出现在月的前面,传入dayfirst=True即可解决这个问题
print(parse('6/12/2011', dayfirst=True)) # 2011-12-06 00:00:00

# to_datetime方法可以解析多种不同日期的表示形式
print(datestrs) # ['7/6/2011', '8/6/2011']
print(pd.to_datetime(datestrs))
'''
DatetimeIndex(['2011-07-06', '2011-08-06'], dtype='datetime64[ns]', freq=None)
'''

# to_datetime也可以处理缺失值(None、空字符串等)
idx = pd.to_datetime(datestrs + [None])
print(idx)
'''
atetimeIndex(['2011-07-06', '2011-08-06', 'NaT'], dtype='datetime64[ns]', freq=None)
'''
print(idx[2]) # NaT , NaT(Not a Time)是pandas中时间戳数据的NA值
print(pd.isnull(idx))  # [False False  True]

2、时间序列基础

dates = [datetime(2011,1,2), datetime(2011, 1, 5), datetime(2011,1,7),
         datetime(2011,1,8), datetime(2011,1,10), datetime(2011,1,12)]
ts = Series(np.random.randn(6), index = dates)
print(ts)
'''
2011-01-02   -0.804594
2011-01-05    0.444492
2011-01-07   -1.336713
2011-01-08    1.380549
2011-01-10   -1.090957
2011-01-12    0.162639
dtype: float64
'''
# datetime对象是被放在一个DatetimeIndex中,现在ts就成为一个TimeSeries了
print(type(ts))
'''
<class 'pandas.core.series.Series'>
DatetimeIndex(['2011-01-02', '2011-01-05', '2011-01-07', '2011-01-08',
               '2011-01-10', '2011-01-12'],
              dtype='datetime64[ns]', freq=None)
'''
print(ts.index)
'''
2011-01-02   -1.609187
2011-01-05         NaN
2011-01-07   -2.673426
2011-01-08         NaN
2011-01-10   -2.181915
2011-01-12         NaN
dtype: float64
'''
# 跟其他Series一样,不同索引的时间序列之间的算术运算会按自动日期对齐
print(ts + ts[::2])
print(ts.index.dtype) # datetime64[ns]
# DatetimeIndex中的各个标量值是pandas的Timestamp对象
stamp = ts.index[0]
print(stamp) # 2011-01-02 00:00:00

2.1 索引、选取、子集构造

dates = [datetime(2011,1,2), datetime(2011, 1, 5), datetime(2011,1,7),
         datetime(2011,1,8), datetime(2011,1,10), datetime(2011,1,12)]
ts = Series(np.random.randn(6), index = dates)
print(ts)
'''
2011-01-02    0.348253
2011-01-05   -0.068450
2011-01-07   -1.073036
2011-01-08    1.059299
2011-01-10    0.497196
2011-01-12    0.713568
dtype: float64
'''
# TimeSeries是Series的一个类,所以在索引以及数据选取方面他们的行为是一样的
stamp=ts.index[2]
print(ts[stamp]) # -1.073035582647907

# 可以传入一个可以解释为日期的字符串
print(ts['1/10/2011']) # 0.4971955016152246
print(ts['20110110'])  # 0.4971955016152246

# 对于较长的时间序列,只需要传入“年”或“年月”即可轻松选取数据的切片
longer_ts = Series(np.random.randn(1000),
                   index=pd.date_range('1/1/2000', periods=1000))
print(longer_ts)
'''
2000-01-01    0.650802
2000-01-02    2.018351
2000-01-03    0.676741
2000-01-04    0.779642
2000-01-05    0.851207
                ...   
2002-09-22   -1.794156
2002-09-23    0.515699
2002-09-24    0.257113
2002-09-25   -1.512441
2002-09-26   -0.680429
Freq: D, Length: 1000, dtype: float64
'''
print(longer_ts['2001'])
'''
2001-01-01    1.357131
2001-01-02   -0.840957
2001-01-03   -1.000980
2001-01-04   -1.183331
2001-01-05    0.453523
                ...   
2001-12-27    0.919488
2001-12-28   -1.240291
2001-12-29    0.061306
2001-12-30   -1.226537
2001-12-31   -0.744249
Freq: D, Length: 365, dtype: float64
'''
print(longer_ts['2001-05'])
'''
2001-05-01    0.377640
2001-05-02    0.389160
2001-05-03   -0.657888
2001-05-04    1.353799
2001-05-05    0.834874
                   ...
2001-05-26   -1.333958
2001-05-27    1.405335
2001-05-28   -0.217538
2001-05-29   -0.029023
2001-05-30   -0.889619
2001-05-31   -0.986640
Freq: D, dtype: float64
'''
# 通过日期进行切片的方式只对规则Series有效
print(ts[datetime(2011,1,7):])
'''
2011-01-07   -1.073036
2011-01-08    1.059299
2011-01-10    0.497196
2011-01-12    0.713568
dtype: float64
'''

# 由于大部分时间都是按照时间先后排序,因此可以用不存在于该时间序列中的时间戳对其进行切片
print(ts)
'''
2011-01-02    0.348253
2011-01-05   -0.068450
2011-01-07   -1.073036
2011-01-08    1.059299
2011-01-10    0.497196
2011-01-12    0.713568
dtype: float64
'''
print(ts['1/6/2011':'1/11/2011'])  # 取范围内的日期
'''
2011-01-07   -1.073036
2011-01-08    1.059299
2011-01-10    0.497196
dtype: float64
'''

# 截取两个日期之间的TimeSeries
print(ts.truncate(after='1/9/2011'))
'''
2011-01-02    0.348253
2011-01-05   -0.068450
2011-01-07   -1.073036
2011-01-08    1.059299
dtype: float64
'''
# 也可以对DataFrame操作,对DataFrame的行进行索引
dates = pd.date_range('1/1/2000',periods = 100, freq='W-WED')
long_df = DataFrame(np.random.randn(100,4),
                    index=dates,
                    columns=['Colorado','Texas', 'NewYork', 'Ohio'])
print(long_df.loc['5-2001'])
'''
            Colorado     Texas   NewYork      Ohio
2001-05-02  1.467936  1.063116  1.344797 -0.580989
2001-05-09  0.637778 -0.905873  0.855643 -1.161038
2001-05-16  0.305796 -1.233853 -0.628636 -0.052159
2001-05-23 -1.098029  0.052049  0.531545  1.161001
2001-05-30 -0.981410 -2.068461  2.049203 -0.786793
'''

2.2 带重复索引的时间序列

dates = pd.DatetimeIndex(['1/1/2000', '1/2/2000', '1/2/2000','1/2/2000', '1/3/2000'])
dup_ts = Series(np.arange(5), index=dates)
print(dup_ts)
'''
2000-01-01    0
2000-01-02    1
2000-01-02    2
2000-01-02    3
2000-01-03    4
dtype: int32
'''

# 通过检查索引的is_unique属性,可以知道它是不是唯一的
print(dup_ts.index.is_unique) # False

# 通过对这个时间序列进行索引,要么产生标量值,要么产生切片,取决于所选的时间点是否重复
print(dup_ts['1/3/2000']) # 4
print(dup_ts['1/2/2000'])
'''
2000-01-02    1
2000-01-02    2
2000-01-02    3
dtype: int32
'''

# 如果想要对具有非唯一的数据进行聚合,可以使用groupby,并传入level=0(索引的唯一一层!)
grouped = dup_ts.groupby(level=0)
print(grouped.mean())
'''
2000-01-01    0
2000-01-02    2
2000-01-03    4
dtype: int32
'''
print(grouped.count())
'''
2000-01-01    1
2000-01-02    3
2000-01-03    1
dtype: int64
'''

3、日期的范围、频率以及移动

# pandas有一套标准时间序列频率以及重采样、频率推断、生成固定频率日期的范围
dates = [datetime(2011,1,2), datetime(2011, 1, 5), datetime(2011,1,7),
         datetime(2011,1,8), datetime(2011,1,10), datetime(2011,1,12)]
ts = Series(np.random.randn(6), index = dates)
print(ts)

ts_resmp = ts.resample('D')
print(ts_resmp)
'''DatetimeIndexResampler [freq=<Day>, axis=0, closed=left, label=left, convention=start, base=0]'''

ts_resmp_sum = ts.resample('3D').sum()
print(ts_resmp_sum) # 按3天重新采样并求和
'''
2011-01-02    1.041772
2011-01-05   -0.854215
2011-01-08   -2.727751
2011-01-11    0.809483
Freq: 3D, dtype: float64
'''
# 关于重采样是比较大的主题,在第6小节专门讨论

3.1 生成日期范围

# 用pandas_range可用于生成指定长度的DatetimeIndex
index = pd.date_range('4/1/2012', '6/1/2012')
print(index[:5])
'''
DatetimeIndex(['2012-04-01', '2012-04-02', '2012-04-03', '2012-04-04',
               '2012-04-05'],
              dtype='datetime64[ns]', freq='D')
'''

# 默认情况下,date_range会按天计算的时间点
# 如果传入起始或起始结束日期,还需要传入一个表示一段时间的数字
print(pd.date_range(start='4/1/2012', 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')
'''
print(pd.date_range(end='6/1/2012',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')
'''

# 生成一个由每月最后一个工作日组成的日期索引,传入“BM"频率(business end of month)
print(pd.date_range('1/1/2000','12/1/2000',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')
'''

# date_range默认保留起始和结束时间戳的时间信息(如果有的话)
print(pd.date_range('5/2/2012 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')
'''

# normalize选项可以实现产生一组被规范化到午夜的时间戳
print(pd.date_range('5/2/2012 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')
'''

3.2 频率和日期偏移量

# pandas中的频率是由一个基础频率和一个乘数组成的
# 基础频率通常以一个字符串别名表示,比如“M"表示每月,”H“表示每小时
from pandas.tseries.offsets import Hour, Minute
hour = Hour()
print(hour) # <Hour>

# 传入一个整数即可定义便宜量的倍数
four_hours = Hour(4)
print(four_hours) # <4 * Hours>

# 在基础频率前面放上一个整数即可创建倍数
print(pd.date_range('1/1/2000', '1/1/2000 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'],
              dtype='datetime64[ns]', freq='4H')
'''

# 大部分偏移量对象都可以通过加法进行连接
print(Hour(2) + Minute(30)) # <150 * Minutes>

# 同时也可以传入频率字符串(如“2h30min”),这种字符串可以被高效地解析为等效的表达式
print(pd.date_range('1/1/2000',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')
'''

# WOM日期,week of month是一种非常实用的频率类,如获得诸如“每月第3个星期五”之类的日期
rng = pd.date_range('1/1/2012','9/1/2012', freq="WOM-3FRI")
print(rng)
'''
DatetimeIndex(['2012-01-20', '2012-02-17', '2012-03-16', '2012-04-20',
               '2012-05-18', '2012-06-15', '2012-07-20', '2012-08-17'],
              dtype='datetime64[ns]', freq='WOM-3FRI')
'''

3.3 移动(超前和滞后)数据

# 移动是指沿着时间轴将数据前移或后移,Series和DataFrame都有一个shift方法用于执行单纯的前移或后移操作
ts = Series(np.random.randn(4),
            index = pd.date_range('1/1/2000', periods=4, freq='M'))
print(ts)
'''
2000-01-31   -0.309081
2000-02-29    0.754501
2000-03-31   -0.727029
2000-04-30   -0.628417
Freq: M, dtype: float64
'''

# Shift通常用于计算一个时间序列或多个时间序列中百分比变化:ts/st.shift(1) - 1
# 如果频率已知,则可以将其传给shift以便实现对时间戳进行位移而不是对数据进行简单位移
print(ts.shift(2, freq='M'))
'''
2000-03-31   -0.309081
2000-04-30    0.754501
2000-05-31   -0.727029
2000-06-30   -0.628417
Freq: M, dtype: float64
'''

# 还可以使用其他频率,可以灵活对数据进行超前或滞后处理
print(ts.shift(3,freq='D'))
'''
2000-02-03   -0.309081
2000-03-03    0.754501
2000-04-03   -0.727029
2000-05-03   -0.628417
dtype: float64
'''

print(ts.shift(1,freq='3D'))
'''
2000-02-03   -0.309081
2000-03-03    0.754501
2000-04-03   -0.727029
2000-05-03   -0.628417
dtype: float64
'''

print(ts.shift(1,freq='90T')) # 1h30mins
'''
2000-01-31 01:30:00   -0.309081
2000-02-29 01:30:00    0.754501
2000-03-31 01:30:00   -0.727029
2000-04-30 01:30:00   -0.628417
Freq: M, dtype: float64
'''
print('----')
# 通过偏移量对日期进行位移
from pandas.tseries.offsets import Day, MonthEnd
now = datetime(2011, 11, 17)
print(now + 3*Day()) # 2011-11-20 00:00:00

# 如果加的是锚点偏移量(MonthEnd例如),第一次增量会将原日期向前滚动到符合频率规则的下一日期
print(now+MonthEnd()) # 2011-11-30 00:00:00
print(now+MonthEnd(2)) # 2011-12-31 00:00:00

# 通过锚点偏移量的rollforward和rollback方法,可显式地将日期向前或向后”滚动“
offset = MonthEnd()
print(offset.rollforward(now)) # 2011-11-30 00:00:00
print(offset.rollback(now)) # 2011-10-31 00:00:00

# 日期偏移量还有一个巧妙的用法,即结合groupby使用这两个“滚动”方法
ts = Series(np.random.randn(20),
            index = pd.date_range('1/15/2000',periods=20,freq='4d'))
print(ts.groupby(offset.rollforward).mean())
'''
2000-01-31    0.168758
2000-02-29   -0.167549
2000-03-31    0.379540
dtype: float64
'''

# 当然实现上述功能最快的方法是使用resample函数
print(ts.resample("M").mean())
'''
2000-01-31    0.168758
2000-02-29   -0.167549
2000-03-31    0.379540
Freq: M, dtype: float64
'''

4、时区处理

# 时区信息来自第三方库Pytz
import pytz
print(pytz.common_timezones[-5:]) # ['US/Eastern', 'US/Hawaii', 'US/Mountain', 'US/Pacific', 'UTC']

# 从pytz中获取时区对象,使用pytz.timezone即可
tz=pytz.timezone('US/Eastern')
print(tz)  # US/Eastern

4.1 本地化和转换

# 默认情况,pandas的时间序列是单纯的(naive)时区
rng = pd.date_range('3/9/2012 9:30', periods=6, freq='D')
ts=Series(np.random.randn(len(rng)), index = rng)
print(ts.index.tz)  # None

# 在生成日期范围的时候还可以加上一个时区集
print(pd.date_range('2/9/2012 9:30', periods=10, freq='D', tz='UTC'))
'''
DatetimeIndex(['2012-02-09 09:30:00+00:00', '2012-02-10 09:30:00+00:00',
               '2012-02-11 09:30:00+00:00', '2012-02-12 09:30:00+00:00',
               '2012-02-13 09:30:00+00:00', '2012-02-14 09:30:00+00:00',
               '2012-02-15 09:30:00+00:00', '2012-02-16 09:30:00+00:00',
               '2012-02-17 09:30:00+00:00', '2012-02-18 09:30:00+00:00'],
              dtype='datetime64[ns, UTC]', freq='D')
'''

# 从单纯到本地化的转换时通过tz_local方法处理的
ts_utc=ts.tz_localize('UTC')
print(ts_utc)
'''
2012-03-09 09:30:00+00:00   -0.366451
2012-03-10 09:30:00+00:00   -1.254051
2012-03-11 09:30:00+00:00    0.733324
2012-03-12 09:30:00+00:00   -0.267528
2012-03-13 09:30:00+00:00   -0.938285
2012-03-14 09:30:00+00:00   -1.037081
Freq: D, dtype: float64
'''

print(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将其转换到别的时区
print(ts_utc.tz_convert('US/Eastern'))
'''
2012-03-09 04:30:00-05:00   -0.366451
2012-03-10 04:30:00-05:00   -1.254051
2012-03-11 05:30:00-04:00    0.733324
2012-03-12 05:30:00-04:00   -0.267528
2012-03-13 05:30:00-04:00   -0.938285
2012-03-14 05:30:00-04:00   -1.037081
Freq: D, dtype: float64
'''

# 对于上面的时间序列(跨越了美国东部时区的夏令时期转变期)可以先将其本地化到EST,再转为UTC或柏林时间
ts_eastern = ts.tz_localize('US/Eastern')
print(ts_eastern.tz_convert('UTC'))
'''
2012-03-09 14:30:00+00:00   -0.366451
2012-03-10 14:30:00+00:00   -1.254051
2012-03-11 13:30:00+00:00    0.733324
2012-03-12 13:30:00+00:00   -0.267528
2012-03-13 13:30:00+00:00   -0.938285
2012-03-14 13:30:00+00:00   -1.037081
dtype: float64
'''
print(ts_eastern.tz_convert('Europe/Berlin'))
'''
2012-03-09 15:30:00+01:00   -0.366451
2012-03-10 15:30:00+01:00   -1.254051
2012-03-11 14:30:00+01:00    0.733324
2012-03-12 14:30:00+01:00   -0.267528
2012-03-13 14:30:00+01:00   -0.938285
2012-03-14 14:30:00+01:00   -1.037081
dtype: float64
'''

# tz_localize和tz_convert也是DatetimeIndex的实例方法
print(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)
'''

4.2 操作时区意识型Timestamp对象

# 与时间序列和日期范围差不多,Timestamp对象也能从单纯型(naive)本地化为时区意识型,并从一个时区转换到另一时区
stamp = pd.Timestamp('2011-03-12 04:00')
stamp_utc = stamp.tz_localize('utc')
print(stamp_utc.tz_convert('US/Eastern')) # 2011-03-11 23:00:00-05:00

# 在创建Timestamp时,还可以传入一个时区信息
stamp_moscow=pd.Timestamp('2011-03-12 04:00', tz='Europe/Moscow')
print(stamp_moscow) # 2011-03-12 04:00:00+03:00

# 时区意识型Timestamp对象在内部保存了一个UTC时间戳值,这个值在时区转换过程中是不会发生变化的
print(stamp_utc.value) # 1299902400000000000
print(stamp_utc.tz_convert('US/Eastern').value) # 1299902400000000000

# 使用pandas的DateOffset对象执行时间算术运算时,运算过程会自动关注是否存在夏令时转变期
# 夏令时转变前30分钟
from pandas.tseries.offsets import Hour
stamp = pd.Timestamp('2012-03-12 01:30', tz='US/Eastern')
print(stamp) # 2012-03-12 01:30:00-04:00
print(stamp+Hour()) # 2012-03-12 02:30:00-04:00

# 夏令时转变前90分钟
stamp=pd.Timestamp('2012-11-04 00:30', tz='US/Eastern')
print(stamp) # 2012-11-04 00:30:00-04:00
print(stamp + 2*Hour())  # 2012-11-04 01:30:00-05:00

4.3 不同时区之间的运算

# 如果两个时间序列的时区不同,将它们合并到一起时,最终结果就会是UTC
# 由于时间戳其实是以UTC储存的,所以这是一个简单的运算,并不需要发生任何转换
rng = pd.date_range('3/7/2012 09:30', periods = 10, freq='B')
ts = Series(np.random.randn(len(rng)), index=rng)
print(ts)
'''
2012-03-07 09:30:00    0.041705
2012-03-08 09:30:00    0.461161
2012-03-09 09:30:00    0.197227
2012-03-12 09:30:00   -1.409566
2012-03-13 09:30:00    0.227489
2012-03-14 09:30:00   -1.624908
2012-03-15 09:30:00    0.717115
2012-03-16 09:30:00   -1.355306
2012-03-19 09:30:00   -1.684638
2012-03-20 09:30:00   -0.566004
Freq: B, dtype: float64
'''
ts1= ts[:7].tz_localize('Europe/London')
ts2= ts1[2:].tz_convert('Europe/Moscow')
result = ts1 + ts2
print(result.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)
'''

5、时期及算术运算

5.1 时期的构建

# 时期表示的是时间区间,如日、数月、数季、数年等
# Period类所表示的就是此种类型,其构造函数需要用到一个字符串或整数,以及频率
p = pd.Period(2007,freq='A-DEC')
print(p) # 2007

# 上述p值表示的是2007年1月1日到2007年12月31日之间的整段时间
# 对Period对象加上或减去一个整数即可达到根据其频率进行位移的效果
print(p+5) # 2012
print(p-2) # 2005

# 如果两个Period对象拥有相同的频率,则他们的差就是他们之间的单位数量
print(pd.Period('2014', freq='A-DEC') - p) # <7 * YearEnds: month=12>

# period_range函数可以用于创建规则的的时期范围
rng = pd.period_range('1/1/2000','6/30/2000', freq='M')
print(rng)
'''
PeriodIndex(['2000-01', '2000-02', '2000-03', '2000-04', '2000-05', '2000-06'], dtype='period[M]', freq='M')
'''

# PeriodIndex类保存了一组Period,可以在任何pandas数据结构中被用作轴索引
print(Series(np.random.randn(6), index = rng))
'''
2000-01   -2.155357
2000-02   -0.912094
2000-03    0.358419
2000-04    0.337311
2000-05    1.036003
2000-06   -0.613236
Freq: M, dtype: float64
'''

# PeriodIndex类的构造函数还允许直接使用一组字符串
values = ['2001Q3', '2002Q2', '2003Q1']
index = pd.PeriodIndex(values, freq='Q-DEC')
print(index)
'''
PeriodIndex(['2001Q3', '2002Q2', '2003Q1'], dtype='period[Q-DEC]', freq='Q-DEC')
'''

5.2 时期的频率转换

# Period和PeriodIndex都可以通过asfreq方法被转换成别的频率
p = pd.Period('2007', freq='A-DEC')
print(p) # 2007
# 转换为一个年初或年末的一个月度时期
print(p.asfreq('M',how='start')) # 2007-01
print(p.asfreq('M',how='end')) # 2007-12

# Period('2007','A-DEC')可以看做一个被划分为多个月度时期的时间段中的游标
p=pd.Period('2007', freq='A-JUN')
print(p.asfreq('M', 'start')) # 2006-07
print(p.asfreq('M', 'end')) # 2007-06

# 高频率转换为低频率时,超时期是由时期所属的位置决定的
# 如,在A-JUN频率中,月份“2007年8月”实际上是属于周期“2008年”的
p=pd.Period('2007-08','M')
print(p.asfreq('A-JUN'))  # 2008

# PeriodIndex或TimeSeries的评率转换方式也是如此
rng =pd.period_range('2006','2009', freq='A-DEC')
ts=Series(np.random.randn(len(rng)), index=rng)
print(ts)
'''
2006   -0.718306
2007    0.273010
2008   -0.441507
2009   -1.229443
Freq: A-DEC, dtype: float64
'''
print(ts.asfreq('M', how='start'))
'''
2006-01   -0.718306
2007-01    0.273010
2008-01   -0.441507
2009-01   -1.229443
Freq: M, dtype: float64
'''
print(ts.asfreq('M', how='end'))
'''
2006-12   -0.718306
2007-12    0.273010
2008-12   -0.441507
2009-12   -1.229443
Freq: M, dtype: float64
'''

   Period频率转换示意图:
在这里插入图片描述

5.3 按季度计算的时期频率

# pandas支持12中可能的季度型频率,即Q-JAN到Q-DEC
# 我的理解,频率是哪个月份,就是那年Q4结束的月份,如本例
p=pd.Period('2012Q4', freq='Q-JAN') 
print(p) # 2012Q4

# 在以1月结束的财年中,2012Q4是从11月到1月
print(p.asfreq('D', 'start')) # 2011-11-01
print(p.asfreq('D', 'end')) # 2012-01-31

# 取该季度倒数第二个工作日下午4点的时间戳
p4pm =(p.asfreq('B', 'e') - 1).asfreq('T', 's') + 16*60
print(p4pm) # 2012-01-30 16:00
print(p4pm.to_timestamp()) # 2012-01-30 16:00:00

# period_range可以用于生产季度型范围
rng = pd.period_range('2011Q3','2012Q4', freq='Q-JAN')
ts=Series(np.arange(len(rng)), index = rng)
print(ts)
'''
2011Q3    0
2011Q4    1
2012Q1    2
2012Q2    3
2012Q3    4
2012Q4    5
Freq: Q-JAN, dtype: int32
'''

new_rng=(rng.asfreq('B', 'e') -1).asfreq('T', 's') + 16*60
ts.index=new_rng.to_timestamp()
print(ts)
'''
2010-10-28 16:00:00    0
2011-01-28 16:00:00    1
2011-04-28 16:00:00    2
2011-07-28 16:00:00    3
2011-10-28 16:00:00    4
2012-01-30 16:00:00    5
dtype: int32
'''

   不同季度频率之间的转换:
在这里插入图片描述

5.4 将Timestamp转化为Period(及其反向过程)

# 通过使用to_period方法,可以将时间戳索引的Series和DataFrame对象转为以时期为索引
rng = pd.date_range('1/1/2000',periods=3,freq='M')
ts = Series(np.random.randn(3), index=rng)
pts=ts.to_period()
print(ts)
'''
2000-01-31    0.563108
2000-02-29    0.784912
2000-03-31    1.014484
Freq: M, dtype: float64
'''
print(pts)
'''
2000-01    0.563108
2000-02    0.784912
2000-03    1.014484
Freq: M, dtype: float64
'''

# 由于时期指的是非重叠时间区间,因此对于给定的频率,一个时间戳只能属于一个时期
rng = pd.date_range('1/29/2000', periods=6, freq='D')
ts2=Series(np.random.randn(6), index=rng)
print(ts2.to_period('M'))
'''
2000-01   -0.139087
2000-01   -0.136360
2000-01   -2.787923
2000-02   -1.520740
2000-02   -0.473269
2000-02    0.600253
Freq: M, dtype: float64
'''

pts=ts.to_period()
print(pts)
'''
2000-01   -0.219983
2000-02   -1.073624
2000-03   -0.681099
Freq: M, dtype: float64
'''
# 转化为时间戳,使用to_timestamp
print(pts.to_timestamp(how='end'))
'''
2000-01-31 23:59:59.999999999   -0.219983
2000-02-29 23:59:59.999999999   -1.073624
2000-03-31 23:59:59.999999999   -0.681099
dtype: float64
'''

5.5 通过数组创建PeriodIndex

# 固定频率的数据集通常会将时间信息分开存放在多列中
data = pd.read_csv('python_data/ch08/macrodata.csv')
print(data.year)
'''
0      1959.0
1      1959.0
2      1959.0
3      1959.0
4      1960.0
        ...  
198    2008.0
199    2008.0
200    2009.0
201    2009.0
202    2009.0
Name: year, Length: 203, dtype: float64
'''
print(data.quarter)
'''
0      1.0
1      2.0
2      3.0
3      4.0
4      1.0
      ... 
198    3.0
199    4.0
200    1.0
201    2.0
202    3.0
Name: quarter, Length: 203, dtype: float64
'''

# 将两个数组以及一个频率传入PeriodIndex,可以将它们合并成DataFrame的一个索引
index = pd.PeriodIndex(year=data.year, quarter=data.quarter, freq='Q-DEC')
print(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 = index
print(data.infl) # infl为data的其中一个属性
'''
1959Q1    0.00
1959Q2    2.34
1959Q3    2.74
1959Q4    0.27
1960Q1    2.31
          ... 
2008Q3   -3.16
2008Q4   -8.79
2009Q1    0.94
2009Q2    3.37
2009Q3    3.56
Freq: Q-DEC, Name: infl, Length: 203, dtype: float64
'''

6、重采样及频率转换

6.1 重采样

# 重采样是将时间序列从一个频率转换到另一个评率的过程
# 将高频率数据聚合到低频率称为讲采样,而将低频率数据转换到高频率则称为升采样
rng = pd.date_range('1/1/2000',periods = 100, freq='D')
ts = Series(np.random.randn(len(rng)), index=rng)
print(ts.resample('M').mean())
'''
2000-01-31    0.066587
2000-02-29   -0.240131
2000-03-31   -0.126769
2000-04-30    0.387274
Freq: M, dtype: float64
'''
print(ts.resample('M', kind='period').mean())
'''
2000-01    0.066587
2000-02   -0.240131
2000-03   -0.126769
2000-04    0.387274
Freq: M, dtype: float64
'''

6.2 降采样

# 降采样是将数据聚合到规整的低频率
rng =pd.date_range('1/1/2000',periods=12,freq='T')
ts=Series(np.arange(12), index=rng)
print(ts)
'''
2000-01-01 00:00:00     0
2000-01-01 00:01:00     1
2000-01-01 00:02:00     2
2000-01-01 00:03:00     3
2000-01-01 00:04:00     4
2000-01-01 00:05:00     5
2000-01-01 00:06:00     6
2000-01-01 00:07:00     7
2000-01-01 00:08:00     8
2000-01-01 00:09:00     9
2000-01-01 00:10:00    10
2000-01-01 00:11:00    11
Freq: T, dtype: int32
'''

# 通过求和的方法将这些数据聚合到“5分钟”块中
print(ts.resample('5min').sum())
'''
2000-01-01 00:00:00    10
2000-01-01 00:05:00    35
2000-01-01 00:10:00    21
Freq: 5T, dtype: int32
'''

# 默认情况下面元的左边界是包含的,因此00:00到00:05区间包含00:05,传入closed='letf'会让区间以左边界闭合
# !!此处跟书中不同,书中是默认包含右边界!!
print(ts.resample('5min', closed='right').sum())
'''
1999-12-31 23:55:00     0
2000-01-01 00:00:00    15
2000-01-01 00:05:00    40
2000-01-01 00:10:00    11
Freq: 5T, dtype: int32
'''

# 时间序列是以各方面左边界的时间戳进行标记的,传入label='right'即可用面元动的右边界对其标记
print(ts.resample('5min',label='right').sum())
'''
2000-01-01 00:05:00    10
2000-01-01 00:10:00    35
2000-01-01 00:15:00    21
Freq: 5T, dtype: int32
'''

# 如果对结果索引做一些位移,如从左边界减去一秒,只需通过loffset设置一个字符串或日期偏移量即可
print(ts.resample('5min',loffset='-1s').sum())
'''
1999-12-31 23:59:59    10
2000-01-01 00:04:59    35
2000-01-01 00:09:59    21
Freq: 5T, dtype: int32
'''

# OHLC重采样,金融领域中有一种无所不在的时间序列聚合方式
# 即计算各面元的四个值,第一个值(开盘)、最后一个值(收盘)、最大值(最高值)、最小值(最低)
# 传入how='ohlc'即可得到一个含有这四种聚合值的DataFrame
print(ts.resample('5min').ohlc())
'''
                     open  high  low  close
2000-01-01 00:00:00     0     4    0      4
2000-01-01 00:05:00     5     9    5      9
2000-01-01 00:10:00    10    11   10     11
'''

# 通过groupby进行重采样
rng = pd.date_range('1/1/2000', periods=100, freq='D')
ts = Series(np.arange(100), index=rng)
print(ts)
print(ts.groupby(lambda x: x.month).mean())
'''
1    15
2    45
3    75
4    95
dtype: int32
'''

print(ts.groupby(lambda x: x.weekday).mean())
'''
0    47.5
1    48.5
2    49.5
3    50.5
4    51.5
5    49.0
6    50.0
dtype: float64
'''

6.3 升采样和差值

# 升采样是指将数据从低频率转换到高频率
frame = DataFrame(np.random.randn(2,4),
                  index=pd.date_range('1/1/2000', periods=2, freq='W-WED'),
                  columns=['Colorado', 'Texas', 'New York', 'Ohio'])
print(frame[:5])
'''
            Colorado     Texas  New York      Ohio
2000-01-05 -0.312261 -1.303667  0.166455  1.113591
2000-01-12 -0.719399  0.860489  0.927483  1.041800
'''

# 将其重采样到日频率,默认会引入缺失值
df_daily = frame.resample('D')
print(df_daily)
'''DatetimeIndexResampler [freq=<Day>, axis=0, closed=left, label=left, convention=start, base=0]'''

# 假如想要用前面的周型填充“非星期三”,resample的填充和差值方式跟fillna和reindex的一样
print(frame.resample('D').ffill())
'''
            Colorado     Texas  New York      Ohio
2000-01-05 -0.312261 -1.303667  0.166455  1.113591
2000-01-06 -0.312261 -1.303667  0.166455  1.113591
2000-01-07 -0.312261 -1.303667  0.166455  1.113591
2000-01-08 -0.312261 -1.303667  0.166455  1.113591
2000-01-09 -0.312261 -1.303667  0.166455  1.113591
2000-01-10 -0.312261 -1.303667  0.166455  1.113591
2000-01-11 -0.312261 -1.303667  0.166455  1.113591
2000-01-12 -0.719399  0.860489  0.927483  1.041800
'''

# 这里可以只填充指定的时期数(目的是限制前面的观测值持续使用)
print(frame.resample('D').ffill(limit=2))
'''
            Colorado     Texas  New York      Ohio
2000-01-05 -0.312261 -1.303667  0.166455  1.113591
2000-01-06 -0.312261 -1.303667  0.166455  1.113591
2000-01-07 -0.312261 -1.303667  0.166455  1.113591
2000-01-08       NaN       NaN       NaN       NaN
2000-01-09       NaN       NaN       NaN       NaN
2000-01-10       NaN       NaN       NaN       NaN
2000-01-11       NaN       NaN       NaN       NaN
2000-01-12 -0.719399  0.860489  0.927483  1.041800
'''

# 新的日期索引完全没有必要跟旧的相交
print(frame.resample('W-THU').ffill())
'''
            Colorado     Texas  New York      Ohio
2000-01-06 -0.312261 -1.303667  0.166455  1.113591
2000-01-13 -0.719399  0.860489  0.927483  1.041800
'''

6.4 通过时期进行重采样

frame = DataFrame(np.random.randn(24,4),
                  index=pd.period_range('1-2000','12-2001',freq='M'),
                  columns=['Colorado', 'Texas', 'New York', 'Ohio'])
print(frame[:5])
'''
         Colorado     Texas  New York      Ohio
2000-01  0.778957  1.395773 -0.554445  1.233439
2000-02  0.858590 -0.382989 -0.655546  1.364961
2000-03  0.064890 -1.007406  2.427516 -0.147838
2000-04  0.654691 -2.857103  0.011106 -0.549523
2000-05  0.290338  0.226746  1.007994  0.673866
'''

annual_frame = frame.resample('A-DEC').mean()
print(annual_frame)
'''
      Colorado     Texas  New York      Ohio
2000  0.406816 -0.262081 -0.186250  0.125175
2001  0.056589  0.340477  0.154083  0.218699
'''

# 升采样稍微麻烦,因为要决定在新的频率中各区间的哪端用于放置原来的值,像asfreq方法
print(annual_frame.resample('Q-DEC').ffill())
'''
        Colorado     Texas  New York      Ohio
2000Q1  0.406816 -0.262081 -0.186250  0.125175
2000Q2  0.406816 -0.262081 -0.186250  0.125175
2000Q3  0.406816 -0.262081 -0.186250  0.125175
2000Q4  0.406816 -0.262081 -0.186250  0.125175
2001Q1  0.056589  0.340477  0.154083  0.218699
2001Q2  0.056589  0.340477  0.154083  0.218699
2001Q3  0.056589  0.340477  0.154083  0.218699
2001Q4  0.056589  0.340477  0.154083  0.218699
'''

print(annual_frame.resample('Q-DEC',convention='end').ffill())
'''
        Colorado     Texas  New York      Ohio
2000Q4  0.406816 -0.262081 -0.186250  0.125175
2001Q1  0.406816 -0.262081 -0.186250  0.125175
2001Q2  0.406816 -0.262081 -0.186250  0.125175
2001Q3  0.406816 -0.262081 -0.186250  0.125175
2001Q4  0.056589  0.340477  0.154083  0.218699
'''

7、时间序列绘图

close_px_all = pd.read_csv('python_data/ch09/stock_px.csv', parse_dates=True,index_col=0)
close_px = close_px_all[['AAPL','MSFT','XOM']]
close_px = close_px.resample('B').ffill()
print(close_px.head())
'''
            AAPL   MSFT    XOM
2003-01-02  7.40  21.11  29.22
2003-01-03  7.45  21.14  29.24
2003-01-06  7.45  21.52  29.96
2003-01-07  7.43  21.93  28.95
2003-01-08  7.28  21.31  28.83
'''

import  matplotlib.pyplot as plt
plt.plot(close_px['AAPL'])
plt.grid(alpha=0.3, linestyle='dashed')
plt.show()

# DataFrame调用plot时,时间序列会被绘制在一个subplot上,并有图例说明
close_px.loc['2009'].plot()
# plt.savefig('10-5.png')
plt.show()

# 苹果公司在2011年1月到3月间的每日股价
close_px['AAPL'].loc['01-2011':'03-2011'].plot()
plt.grid(alpha=0.3, linestyle='dashed')
#plt.savefig('10-6.png')
plt.show()

# 季度型频率数据会用季度标记进行格式化
appl_q=close_px['AAPL'].resample('Q-DEC').ffill()
appl_q.loc['2009':].plot()
plt.grid(alpha=0.3, linestyle='dashed')
#plt.savefig('10-7.png')
plt.show()

       以下图片对应原书中的图片序号,按代码输出顺序给出(其他段落同样):
       图10-4 AAPL每日价格:

在这里插入图片描述

       图10-5 2009年股票价格:
在这里插入图片描述

       图10-6 苹果公司在2011年1月到3月的每日股价:
在这里插入图片描述

       图10-7 苹果公司在2009年到2011年的每季度价格:
在这里插入图片描述

8、移动窗口函数

8.1 移动窗口

# 在移动窗口上计算各种统计函数是一类常见于时间序列的数组变换
# rolling_mean是其中最简单的一个,它接受一个TimeSeries或DataFrame以及一个window(表示期数)
close_px_all = pd.read_csv('python_data/ch09/stock_px.csv', parse_dates=True,index_col=0)
close_px = close_px_all[['AAPL','MSFT','XOM']]
close_px = close_px.resample('B').ffill()
close_px.AAPL.plot()
close_px.AAPL.rolling(250).mean().plot()
plt.grid(alpha=0.3, linestyle='dashed')
plt.show()

appl_std250=close_px.AAPL.rolling(250, min_periods=10).std()
print(appl_std250[5:12])
'''
2003-01-09         NaN
2003-01-10         NaN
2003-01-13         NaN
2003-01-14         NaN
2003-01-15    0.077496
2003-01-16    0.074760
2003-01-17    0.112368
Freq: B, Name: AAPL, dtype: float64
'''

appl_std250.plot()
plt.grid(alpha=0.3, linestyle='dashed')
plt.show()

# 要计算扩展窗口平均,可以将扩展窗口看做一个特殊的窗口,其长度与时间序列一样,但只需一期(或多期)即可计算一个值
# 通过rolling().mean()定义扩展平均
expanding_mean = lambda x: x.rolling(len(x), min_periods=1).mean()
# 对DataFrame调用rolling_mean(以及与之类似的函数)会将转换应用到所有列上
close_px.rolling(60).mean().plot(logy=True)
plt.grid(alpha=0.3, linestyle='dashed')
plt.show()

       图10-8 苹果公司的250的股票均线:
在这里插入图片描述

       图10-9 苹果公司的250日每日回报标准差:
在这里插入图片描述

       图10-10 各公司60日均线(对数Y轴):
在这里插入图片描述

8.2 指数加权函数

# 另一种使用固定大小窗口及相等权数观测值得办法是,定义一个衰减因子常量,以便使最近的观测值拥有更大的权数
fig,axes = plt.subplots(2,1, sharex=True, sharey=True, figsize=(12,7))
aapl_px = close_px.AAPL['2005': '2009']

# 对比苹果公司股价的60日移动平均和span=60的指数加权移动平均
ma60 = aapl_px.rolling(60, min_periods=50).mean()
ewma60 = pd.DataFrame.ewm(aapl_px,span=60).mean()
aapl_px.plot(style='k-', ax = axes[0])
ma60.plot(style='k--', ax = axes[0])
aapl_px.plot(style='k-', ax = axes[1])
ewma60.plot(style='k--', ax = axes[1])
axes[0].set_title('Simple MA')
axes[1].set_title('Exponentially-weithed MA')
axes[0].grid(alpha=0.3, linestyle='dashed')
axes[1].grid(alpha=0.3, linestyle='dashed')
plt.show()

       图10-11 简单移动平均与指数加权移动平均:
在这里插入图片描述

8.3 二次移动窗口函数

# 有些运算需(如相关系数和协方差)需要在两个时间序列上执行
# 通过计算百分数变化并使用rolling_corr的方式得到该结果
spx_px = close_px_all['SPX']
spx_rets = spx_px/spx_px.shift(1)-1
returns = close_px.pct_change()
corr = returns.AAPL.rolling(125, min_periods=100).corr(spx_rets)
corr.plot()
plt.grid(alpha=0.3, linestyle='dashed')
plt.show()

# 计算DataFrame各列与标准普尔500指数的相关系数
corr = returns.rolling(125,min_periods=100).corr(spx_rets)
corr.plot()
plt.grid(alpha=0.3, linestyle='dashed')
plt.show()

       图10-12 AAPL6个月的回报与标准普尔500指数的相关系数:
在这里插入图片描述

       图10-13 3只股票6个月的回报与标准普尔500指数的相关系数:
在这里插入图片描述

8.4 用户定义的移动窗口函数

# rolling apply()函数可以在移动窗口上应用自己设计的数组函数
from scipy.stats import percentileofscore
scroe_at_2percent = lambda x: percentileofscore(x, 0.02)
result = returns.AAPL.rolling(250).apply(scroe_at_2percent)
result.plot()
plt.grid(alpha=0.3, linestyle='dashed')
plt.show()

       图10-14 AAPL 2%回报率的百分登记(一年窗口期):
在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zhou4411781/article/details/108848312

智能推荐

从零开始搭建Hadoop_创建一个hadoop项目-程序员宅基地

文章浏览阅读331次。第一部分:准备工作1 安装虚拟机2 安装centos73 安装JDK以上三步是准备工作,至此已经完成一台已安装JDK的主机第二部分:准备3台虚拟机以下所有工作最好都在root权限下操作1 克隆上面已经有一台虚拟机了,现在对master进行克隆,克隆出另外2台子机;1.1 进行克隆21.2 下一步1.3 下一步1.4 下一步1.5 根据子机需要,命名和安装路径1.6 ..._创建一个hadoop项目

心脏滴血漏洞HeartBleed CVE-2014-0160深入代码层面的分析_heartbleed代码分析-程序员宅基地

文章浏览阅读1.7k次。心脏滴血漏洞HeartBleed CVE-2014-0160 是由heartbeat功能引入的,本文从深入码层面的分析该漏洞产生的原因_heartbleed代码分析

java读取ofd文档内容_ofd电子文档内容分析工具(分析文档、签章和证书)-程序员宅基地

文章浏览阅读1.4k次。前言ofd是国家文档标准,其对标的文档格式是pdf。ofd文档是容器格式文件,ofd其实就是压缩包。将ofd文件后缀改为.zip,解压后可看到文件包含的内容。ofd文件分析工具下载:点我下载。ofd文件解压后,可以看到如下内容: 对于xml文件,可以用文本工具查看。但是对于印章文件(Seal.esl)、签名文件(SignedValue.dat)就无法查看其内容了。本人开发一款ofd内容查看器,..._signedvalue.dat

基于FPGA的数据采集系统(一)_基于fpga的信息采集-程序员宅基地

文章浏览阅读1.8w次,点赞29次,收藏313次。整体系统设计本设计主要是对ADC和DAC的使用,主要实现功能流程为:首先通过串口向FPGA发送控制信号,控制DAC芯片tlv5618进行DA装换,转换的数据存在ROM中,转换开始时读取ROM中数据进行读取转换。其次用按键控制adc128s052进行模数转换100次,模数转换数据存储到FIFO中,再从FIFO中读取数据通过串口输出显示在pc上。其整体系统框图如下:图1:FPGA数据采集系统框图从图中可以看出,该系统主要包括9个模块:串口接收模块、按键消抖模块、按键控制模块、ROM模块、D.._基于fpga的信息采集

微服务 spring cloud zuul com.netflix.zuul.exception.ZuulException GENERAL-程序员宅基地

文章浏览阅读2.5w次。1.背景错误信息:-- [http-nio-9904-exec-5] o.s.c.n.z.filters.post.SendErrorFilter : Error during filteringcom.netflix.zuul.exception.ZuulException: Forwarding error at org.springframework.cloud..._com.netflix.zuul.exception.zuulexception

邻接矩阵-建立图-程序员宅基地

文章浏览阅读358次。1.介绍图的相关概念  图是由顶点的有穷非空集和一个描述顶点之间关系-边(或者弧)的集合组成。通常,图中的数据元素被称为顶点,顶点间的关系用边表示,图通常用字母G表示,图的顶点通常用字母V表示,所以图可以定义为:  G=(V,E)其中,V(G)是图中顶点的有穷非空集合,E(G)是V(G)中顶点的边的有穷集合1.1 无向图:图中任意两个顶点构成的边是没有方向的1.2 有向图:图中..._给定一个邻接矩阵未必能够造出一个图

随便推点

MDT2012部署系列之11 WDS安装与配置-程序员宅基地

文章浏览阅读321次。(十二)、WDS服务器安装通过前面的测试我们会发现,每次安装的时候需要加域光盘映像,这是一个比较麻烦的事情,试想一个上万个的公司,你天天带着一个光盘与光驱去给别人装系统,这将是一个多么痛苦的事情啊,有什么方法可以解决这个问题了?答案是肯定的,下面我们就来简单说一下。WDS服务器,它是Windows自带的一个免费的基于系统本身角色的一个功能,它主要提供一种简单、安全的通过网络快速、远程将Window..._doc server2012上通过wds+mdt无人值守部署win11系统.doc

python--xlrd/xlwt/xlutils_xlutils模块可以读xlsx吗-程序员宅基地

文章浏览阅读219次。python–xlrd/xlwt/xlutilsxlrd只能读取,不能改,支持 xlsx和xls 格式xlwt只能改,不能读xlwt只能保存为.xls格式xlutils能将xlrd.Book转为xlwt.Workbook,从而得以在现有xls的基础上修改数据,并创建一个新的xls,实现修改xlrd打开文件import xlrdexcel=xlrd.open_workbook('E:/test.xlsx') 返回值为xlrd.book.Book对象,不能修改获取sheett_xlutils模块可以读xlsx吗

关于新版本selenium定位元素报错:‘WebDriver‘ object has no attribute ‘find_element_by_id‘等问题_unresolved attribute reference 'find_element_by_id-程序员宅基地

文章浏览阅读8.2w次,点赞267次,收藏656次。运行Selenium出现'WebDriver' object has no attribute 'find_element_by_id'或AttributeError: 'WebDriver' object has no attribute 'find_element_by_xpath'等定位元素代码错误,是因为selenium更新到了新的版本,以前的一些语法经过改动。..............._unresolved attribute reference 'find_element_by_id' for class 'webdriver

DOM对象转换成jQuery对象转换与子页面获取父页面DOM对象-程序员宅基地

文章浏览阅读198次。一:模态窗口//父页面JSwindow.showModalDialog(ifrmehref, window, 'dialogWidth:550px;dialogHeight:150px;help:no;resizable:no;status:no');//子页面获取父页面DOM对象//window.showModalDialog的DOM对象var v=parentWin..._jquery获取父window下的dom对象

什么是算法?-程序员宅基地

文章浏览阅读1.7w次,点赞15次,收藏129次。算法(algorithm)是解决一系列问题的清晰指令,也就是,能对一定规范的输入,在有限的时间内获得所要求的输出。 简单来说,算法就是解决一个问题的具体方法和步骤。算法是程序的灵 魂。二、算法的特征1.可行性 算法中执行的任何计算步骤都可以分解为基本可执行的操作步,即每个计算步都可以在有限时间里完成(也称之为有效性) 算法的每一步都要有确切的意义,不能有二义性。例如“增加x的值”,并没有说增加多少,计算机就无法执行明确的运算。 _算法

【网络安全】网络安全的标准和规范_网络安全标准规范-程序员宅基地

文章浏览阅读1.5k次,点赞18次,收藏26次。网络安全的标准和规范是网络安全领域的重要组成部分。它们为网络安全提供了技术依据,规定了网络安全的技术要求和操作方式,帮助我们构建安全的网络环境。下面,我们将详细介绍一些主要的网络安全标准和规范,以及它们在实际操作中的应用。_网络安全标准规范