《利用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

智能推荐

分布式光纤传感器的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告_预计2026年中国分布式传感器市场规模有多大-程序员宅基地

文章浏览阅读3.2k次。本文研究全球与中国市场分布式光纤传感器的发展现状及未来发展趋势,分别从生产和消费的角度分析分布式光纤传感器的主要生产地区、主要消费地区以及主要的生产商。重点分析全球与中国市场的主要厂商产品特点、产品规格、不同规格产品的价格、产量、产值及全球和中国市场主要生产商的市场份额。主要生产商包括:FISO TechnologiesBrugg KabelSensor HighwayOmnisensAFL GlobalQinetiQ GroupLockheed MartinOSENSA Innovati_预计2026年中国分布式传感器市场规模有多大

07_08 常用组合逻辑电路结构——为IC设计的延时估计铺垫_基4布斯算法代码-程序员宅基地

文章浏览阅读1.1k次,点赞2次,收藏12次。常用组合逻辑电路结构——为IC设计的延时估计铺垫学习目的:估计模块间的delay,确保写的代码的timing 综合能给到多少HZ,以满足需求!_基4布斯算法代码

OpenAI Manager助手(基于SpringBoot和Vue)_chatgpt网页版-程序员宅基地

文章浏览阅读3.3k次,点赞3次,收藏5次。OpenAI Manager助手(基于SpringBoot和Vue)_chatgpt网页版

关于美国计算机奥赛USACO,你想知道的都在这_usaco可以多次提交吗-程序员宅基地

文章浏览阅读2.2k次。USACO自1992年举办,到目前为止已经举办了27届,目的是为了帮助美国信息学国家队选拔IOI的队员,目前逐渐发展为全球热门的线上赛事,成为美国大学申请条件下,含金量相当高的官方竞赛。USACO的比赛成绩可以助力计算机专业留学,越来越多的学生进入了康奈尔,麻省理工,普林斯顿,哈佛和耶鲁等大学,这些同学的共同点是他们都参加了美国计算机科学竞赛(USACO),并且取得过非常好的成绩。适合参赛人群USACO适合国内在读学生有意向申请美国大学的或者想锻炼自己编程能力的同学,高三学生也可以参加12月的第_usaco可以多次提交吗

MySQL存储过程和自定义函数_mysql自定义函数和存储过程-程序员宅基地

文章浏览阅读394次。1.1 存储程序1.2 创建存储过程1.3 创建自定义函数1.3.1 示例1.4 自定义函数和存储过程的区别1.5 变量的使用1.6 定义条件和处理程序1.6.1 定义条件1.6.1.1 示例1.6.2 定义处理程序1.6.2.1 示例1.7 光标的使用1.7.1 声明光标1.7.2 打开光标1.7.3 使用光标1.7.4 关闭光标1.8 流程控制的使用1.8.1 IF语句1.8.2 CASE语句1.8.3 LOOP语句1.8.4 LEAVE语句1.8.5 ITERATE语句1.8.6 REPEAT语句。_mysql自定义函数和存储过程

半导体基础知识与PN结_本征半导体电流为0-程序员宅基地

文章浏览阅读188次。半导体二极管——集成电路最小组成单元。_本征半导体电流为0

随便推点

【Unity3d Shader】水面和岩浆效果_unity 岩浆shader-程序员宅基地

文章浏览阅读2.8k次,点赞3次,收藏18次。游戏水面特效实现方式太多。咱们这边介绍的是一最简单的UV动画(无顶点位移),整个mesh由4个顶点构成。实现了水面效果(左图),不动代码稍微修改下参数和贴图可以实现岩浆效果(右图)。有要思路是1,uv按时间去做正弦波移动2,在1的基础上加个凹凸图混合uv3,在1、2的基础上加个水流方向4,加上对雾效的支持,如没必要请自行删除雾效代码(把包含fog的几行代码删除)S..._unity 岩浆shader

广义线性模型——Logistic回归模型(1)_广义线性回归模型-程序员宅基地

文章浏览阅读5k次。广义线性模型是线性模型的扩展,它通过连接函数建立响应变量的数学期望值与线性组合的预测变量之间的关系。广义线性模型拟合的形式为:其中g(μY)是条件均值的函数(称为连接函数)。另外,你可放松Y为正态分布的假设,改为Y 服从指数分布族中的一种分布即可。设定好连接函数和概率分布后,便可以通过最大似然估计的多次迭代推导出各参数值。在大部分情况下,线性模型就可以通过一系列连续型或类别型预测变量来预测正态分布的响应变量的工作。但是,有时候我们要进行非正态因变量的分析,例如:(1)类别型.._广义线性回归模型

HTML+CSS大作业 环境网页设计与实现(垃圾分类) web前端开发技术 web课程设计 网页规划与设计_垃圾分类网页设计目标怎么写-程序员宅基地

文章浏览阅读69次。环境保护、 保护地球、 校园环保、垃圾分类、绿色家园、等网站的设计与制作。 总结了一些学生网页制作的经验:一般的网页需要融入以下知识点:div+css布局、浮动、定位、高级css、表格、表单及验证、js轮播图、音频 视频 Flash的应用、ul li、下拉导航栏、鼠标划过效果等知识点,网页的风格主题也很全面:如爱好、风景、校园、美食、动漫、游戏、咖啡、音乐、家乡、电影、名人、商城以及个人主页等主题,学生、新手可参考下方页面的布局和设计和HTML源码(有用点赞△) 一套A+的网_垃圾分类网页设计目标怎么写

C# .Net 发布后,把dll全部放在一个文件夹中,让软件目录更整洁_.net dll 全局目录-程序员宅基地

文章浏览阅读614次,点赞7次,收藏11次。之前找到一个修改 exe 中 DLL地址 的方法, 不太好使,虽然能正确启动, 但无法改变 exe 的工作目录,这就影响了.Net 中很多获取 exe 执行目录来拼接的地址 ( 相对路径 ),比如 wwwroot 和 代码中相对目录还有一些复制到目录的普通文件 等等,它们的地址都会指向原来 exe 的目录, 而不是自定义的 “lib” 目录,根本原因就是没有修改 exe 的工作目录这次来搞一个启动程序,把 .net 的所有东西都放在一个文件夹,在文件夹同级的目录制作一个 exe._.net dll 全局目录

BRIEF特征点描述算法_breif description calculation 特征点-程序员宅基地

文章浏览阅读1.5k次。本文为转载,原博客地址:http://blog.csdn.net/hujingshuang/article/details/46910259简介 BRIEF是2010年的一篇名为《BRIEF:Binary Robust Independent Elementary Features》的文章中提出,BRIEF是对已检测到的特征点进行描述,它是一种二进制编码的描述子,摈弃了利用区域灰度..._breif description calculation 特征点

房屋租赁管理系统的设计和实现,SpringBoot计算机毕业设计论文_基于spring boot的房屋租赁系统论文-程序员宅基地

文章浏览阅读4.1k次,点赞21次,收藏79次。本文是《基于SpringBoot的房屋租赁管理系统》的配套原创说明文档,可以给应届毕业生提供格式撰写参考,也可以给开发类似系统的朋友们提供功能业务设计思路。_基于spring boot的房屋租赁系统论文