数学建模pandas学习(第十天)

数学建模pandas学习



一.Python Pandas时间序列详解

顾名思义,时间序列(time series),就是由时间构成的序列,它指的是在一定时间内按照时间顺序测量的某个变量的取值序列,比如一天内的温度会随时间而发生变化,或者股票的价格会随着时间不断的波动,这里用到的一系列时间,就可以看做时间序列。时间序列包含三种应用场景,分别是:

  • 特定的时刻(timestamp),也就是时间戳;
  • 固定的日期(period),比如某年某月某日;
  • 时间间隔(interval),每隔一段时间具有规律性;
    在处理时间序列的过程中,我们一般会遇到两个问题,第一,如何创建时间序列;第二,如何更改已生成时间序列的频率。 Pandas 为解决上述问题提供了一套简单、易用的方法。
    下面用 Python 内置的 datetime 模块来获取当前时间,通过该模块提供的now()方法即可实现。
from datetime import datetime
#数据类型为datetime
print(datetime.now())

创建时间戳

TimeStamp(时间戳) 是时间序列中的最基本的数据类型,它将数值与时间点完美结合在一起。Pandas 使用下列方法创建时间戳:

import pandas as pd
print (pd.Timestamp('2017-03-01'))

同样,可以将整型或浮点型表示的时间转换为时间戳。默认的单位是纳秒(时间戳单位),示例如下:

import pandas as pd
print(pd.Timestamp(1587687255,unit='s'))

创建时间范围

通过 date_range() 方法可以创建某段连续的时间或者固定间隔的时间时间段。该函数提供了三个参数,分别是:

  • start:开始时间
  • end:结束时间
  • freq:时间频率,默认为 “D”(天)
import pandas as pd
#freq表示时间频率,每30min变化一次
print(pd.date_range("9:00", "18:10", freq="30min").time)

更改时间频率

import pandas as pd
#修改为按小时
print(pd.date_range("6:10", "11:45", freq="H").time)

转化为时间戳

您可以使用 to_datetime() 函数将 series 或 list 转换为日期对象,其中 list 会转换为DatetimeIndex。示例如下:

import pandas as pd
print(pd.to_datetime(pd.Series(['Jun 3, 2020','2020-12-10', None])))

例二:

import pandas as pd
#传入list,生成Datetimeindex
print(pd.to_datetime(['Jun 31, 2020','2020-12-10', None]))

频率和周期转换

Time Periods 表示时间跨度,一段时间周期,它被定义在 Pandas Periods 类中,通过该类提供的方法可以实现将频率转换为周期。比如 Periods() 方法,可以将频率 “M”(月)转换为 Period(时间段)。

import pandas as pd 
x = pd.Period('2014', freq='M')
#start参数
x.asfreq('D', 'start')
#end参数
x.asfreq('D', 'end')

对于常用的时间序列频率,Pandas 为其规定了一些字符串别名,我们将这些别名称为“offset(偏移量)”。如下表所示:

别名 描述 别名 描述

  • B 工作日频率 BQS 工作季度开始频率
  • D 日历日频率 A 年终频率
  • W 每周频率 BA 工作年度结束频率
  • M 月末频率 BAS 工作年度开始频率
  • SM 半月结束频率 BH 营业时间频率
  • BM 工作月结束频率 H 小时频率
  • MS 月开始频率 T,min 每分钟频率
  • SMS 半月开始频率 S 每秒钟频率
  • BMS 工作月开始频率 L,ms 毫秒
  • Q 季末频率 U,us 微妙
  • BQ 工作季度结束频率 N 纳秒
  • QS 季度开始频率

时间周期计算

周期计算,指的是对时间周期进行算术运算,所有的操作将在“频率”的基础上执行。

import pandas as pd 
#S表示秒
x = pd.Period('2014', freq='S')  
x

执行计算示例:

import pandas as pd 
x = pd.Period('2014', freq='S')
#加1s的时间
print(x+1)

再看一组完整的示例:

#定义时期period,默认freq="Y"年份
p1=pd.Period('2020')
p2=pd.Period('2019')
#使用f''格式化输出
print(f'p1={p1}年')
print(f'p2={p2}年')
print(f'p1和p2间隔{p1-p2}年')
#f''表示字符串格式化输出
print(f'五年前是{p1-5}年')

创建时间周期

我们可以使用 period_range() 方法来创建时间周期范围。示例如下:

import pandas as pd
#Y表示年
p = pd.period_range('2016','2018', freq='Y')
print(p)

时间序列转换

如果想要把字符串日期转换为 Period,首先需要将字符串转换为日期格式,然后再将日期转换为 Period。示例如下:

# 创建时间序列
index=pd.date_range("2020-03-17","2020-03-30",freq="1.5H")
#随机选取4个互不相同的数
loc=np.random.choice(np.arange(len(index)),size=4,replace=False)
loc.sort()
ts_index=index[loc]
ts_index
pd_index=ts_index.to_periods('D')
pd_index()

使用 to_timestamp() 能够将 Period 时期转换为时间戳(timestamp),示例如下:

import pandas as pd
p1=pd.Periods("2020-2-3")
p1.to_timestamp()

创建日期范围

Pandas 提供了用来创建日期序列的函数 date_range(),该函数的默认频率为 “D”, 也就是“天”。日期序列只包含年、月、日,不包含时、分、秒。

import pandas as pd
print(pd.date_range('12/15/2020', periods=10))

当我们使用 date_range() 来创建日期范围时,该函数包含结束的日期,用数学术语来说就是区间左闭右闭,即包含起始值,也包含结束值。示例如下:

import pandas as pd
#建议使用Python的datetime模块创建时间
start = pd.datetime(2019, 1, 1)
end = pd.datetime(2019, 1, 5)
print pd.date_range(start,end)

更改日频率

使用下列方法可以修改频率,比如按“天”为按“月”,示例如下:

import pandas as pd
print(pd.date_range('12/15/2011', periods=5,freq='M'))

工作日时间

bdate_range() 表示创建工作日的日期范围,它与 date_range() 不同,它不包括周六、周日。

import pandas as pd
print(pd.bdate_range('11/25/2020', periods=8))

二.Pandas日期时间格式化

当进行数据分析时,我们会遇到很多带有日期、时间格式的数据集,在处理这些数据集时,可能会遇到日期格式不统一的问题,此时就需要对日期时间做统一的格式化处理。比如“Wednesday, June 6, 2020”可以写成“6/6/20”,或者写成“06-06-2020。

日期格式化符号

在对时间进行格式化处理时,它们都有固定的表示格式,比如小时的格式化符号为%H ,分钟简写为%M ,秒简写为%S。下表对常用的日期格式化符号做了总结:

日期格式化符号
符号 说明

  • %y 两位数的年份表示(00-99)
  • %Y 四位数的年份表示(000-9999)
  • %m 月份(01-12)
  • %d 月内中的一天(0-31)
  • %H 24小时制小时数(0-23)
  • %I 12小时制小时数(01-12)
  • %M 分钟数(00=59)
  • %S 秒(00-59)
  • %a 本地英文缩写星期名称
  • %A 本地英文完整星期名称
  • %b 本地缩写英文的月份名称
  • %B 本地完整英文的月份名称
  • %w 星期(0-6),星期天为星期的开始
  • %W 一年中的星期数(00-53)星期一为星期的开始
  • %x 本地相应的日期表示
  • %X 本地相应的时间表示
  • %Z 当前时区的名称
  • %U 一年中的星期数(00-53)星期天为星期的开始
  • %j 年内的一天(001-366)
  • %c 本地相应的日期表示和时间表示

Python处理

Python 内置的 strptime() 方法能够将字符串日期转换为 datetime 类型,下面看一组示例:

from datetime import datetime
#将日期定义为字符串    
date_str1 = 'Wednesday, July 18, 2020' 
date_str2 = '18/7/20' 
date_str3 = '18-07-2020'  
#将日期转化为datetime对象 
dmy_dt1 = datetime.strptime(date_str1, '%A,%B%d,%Y') 
dmy_dt2 = datetime.strptime(date_str2, '%d/%m/%y') 
dmy_dt3 = datetime.strptime(date_str3, '%d-%m-%Y')  
#处理为相同格式,并打印输出
print(dmy_dt1) 
print(dmy_dt2) 
print(dmy_dt3) 

注意:strftime() 可以将 datetime 类型转换为字符串类型,恰好与 strptime() 相反。

Pandas处理

除了使用 Python 内置的 strptime() 方法外,你还可以使用 Pandas 模块的 pd.to_datetime() 和 pd.DatetimeIndex() 进行转换。

1) to_datetime()

通过 to_datetime() 直接转换为 datetime 类型

import pandas as pd
import numpy as np
date = ['2012-05-06 11:00:00','2012-05-16 11:00:00']
pd_date=pd.to_datetime(date)
df=pd.Series(np.random.randn(2),index=pd_date)
2) DatetimeIndex()
date = pd.DatetimeIndex(['1/1/2008', '1/2/2008', '1/3/2008', '1/4/2008', '1/5/2008'])
dt = pd.Series(np.random.randn(5),index = date)
print(dt)

三.Padans Timedelta时间差

Timedelta 表示时间差(或者时间增量),我们可以使用不同的时间单位来表示它,比如,天、小时、分、秒。时间差的最终的结果可以是正时间差,也可以是负时间差。
本节主要介绍创建 Timedelta (时间差)的方法以及与时间差相关的运算法则。

字符串

通过传递字符串可以创建 Timedelta 对象,示例如下:

import pandas as pd
print(pd.Timedelta('5 days 8 hours 6 minutes 59 seconds'))

整数

通过传递整数值和unit参数也可以创建一个 Timedelta 对象。
import pandas as pd
print(pd.Timedelta(19,unit=‘h’))

数据偏移量

数据偏移量, 比如,周(weeks)、天(days)、小时(hours)、分钟(minutes)、秒(milliseconds)、毫秒、微秒、纳秒都可以使用。

import pandas as pd
print (pd.Timedelta(days=2,hours=6))

to_timedelta()

您可以使用pd.to_timedelta()方法,将具有 timedelta 格式的值 (标量、数组、列表或 Series)转换为 Timedelta 类型。如果输入是 Series,则返回 Series;如果输入是标量,则返回值也为标量,其他情况输出 TimedeltaIndex。示例如下:

import pandas as pd
print(pd.to_timedelta(['1 days 06:05:01.00003', '15.5us', 'nan']))
print(pd.to_timedelta(np.arange(5), unit='s'))

算术操作

通过对datetime64[ns]类型的时间序列或时间戳做算术运算,其运算结果依然是datetime64[ns]数据类型。接下来,我们创建一个带有 Timedelta 与 datetime 的 DataFrame 对象,并对其做一些算术运算。

import pandas as pd
s = pd.Series(pd.date_range('2020-1-1', periods=5, freq='D'))
#推导式用法
td = pd.Series([ pd.Timedelta(days=i) for i in range(5)])
df = pd.DataFrame(dict(A = s, B = td))
print(df)

加法运算

import pandas as pd
s = pd.Series(pd.date_range('20120-1-1', periods=3, freq='D'))
td = pd.Series([ pd.Timedelta(days=i) for i in range(3) ])
df = pd.DataFrame(dict(A = s, B = td))
#加法运算
df['C']=df['A']+df['B']
print(df)

减法运算

import pandas as pd
s = pd.Series(pd.date_range('2012-1-1', periods=3, freq='D'))
td = pd.Series([ pd.Timedelta(days=i) for i in range(3) ])
df = pd.DataFrame(dict(A = s, B = td))
df['C']=df['A']+df['B']
df['D']=df['C']-df['B']
print(df)

四.Pandas sample随机抽样

随机抽样,是统计学中常用的一种方法,它可以帮助我们从大量的数据中快速地构建出一组数据分析模型。在 Pandas 中,如果想要对数据集进行随机抽样,需要使用 sample() 函数。
sample() 函数的语法格式如下:

DataFrame.sample(n=None, frac=None, replace=False, weights=None, random_state=None, axis=None)

参数名称 参数说明

  • n 表示要抽取的行数。
  • frac 表示抽取的比例,比如 frac=0.5,代表抽取总体数据的50%。
  • replace 布尔值参数,表示是否以有放回抽样的方式进行选择,默认为 + False,取出数据后不再放回。
  • weights 可选参数,代表每个样本的权重值,参数值是字符串或者数组。
  • random_state 可选参数,控制随机状态,默认为 None,表示随机数据不 会重复;若为 1 表示会取得重复数据。
  • axis 表示在哪个方向上抽取数据(axis=1 表示列/axis=0 表示行)。
    该函数返回与数据集类型相同的新对象,相当于 numpy.random.choice()。实例如下:
import pandas as pd  
dict = {'name':["Jack", "Tom", "Helen", "John"],'age': [28, 39, 34, 36],'score':[98,92,91,89]} 
info = pd.DataFrame(dict)
#默认随机选择两行
info.sample(n=2)
#随机选择两列
info.sample(n=2,axis=1)

import pandas as pd
info = pd.DataFrame({‘data1’: [2, 6, 8, 0], ‘data2’: [2, 5, 0, 8], ‘data3’: [12, 2, 1, 8]}, index=[‘John’, ‘Parker’, ‘Smith’, ‘William’])
info
#随机抽取3个数据
info[‘data1’].sample(n=3)
#总体的50%
info.sample(frac=0.5, replace=True)
#data3序列为权重值,并且允许重复数据出现
info.sample(n=2, weights=‘data3’, random_state=1)

五.Pandas resample数据重采样

数据重采样是将时间序列从一个频率转换至另一个频率的过程,它主要有两种实现方式,分别是降采样和升采样,降采样指将高频率的数据转换为低频率,升采样则与其恰好相反,说明如下:

方法 说明

  • 降采样 将高频率(间隔短)数据转换为低频率(间隔长)。
  • 升采样 将低频率数据转换为高频率。

降采样

通过 resample() 函数完成数据的降采样,比如按天计数的频率转换为按月计数。

import pandas as pd
import numpy as np
rng = pd.date_range('1/1/2021',periods=100,freq='D')
ts = pd.Series(np.random.randn(len(rng)),index=rng)
#降采样后并聚合
ts.resample('M').mean()

如果您只想看到月份,那么您可以设置kind=period如下所示:

ts.resample(‘M’,kind=‘period’).mean()

升采样

升采样是将低频率(时间间隔)转换为高频率,示例如下:

import pandas as pd
import numpy as np
#生成一份时间序列数据
rng = pd.date_range('1/1/2021', periods=20, freq='3D')
ts = pd.Series(np.random.randn(len(rng)), index=rng)
print(ts.head())
#使用asfreq()在原数据基础上实现频率转换
ts.resample('D').asfreq().head()

频率转换

asfreq() 方法不仅能够实现频率转换,还可以保留原频率对应的数值,同时它也可以单独使用,示例如下:
index = pd.date_range(‘1/1/2021’, periods=6, freq=‘T’)
series = pd.Series([0.0, None, 2.0, 3.0,4.0,5.0], index=index)
df = pd.DataFrame({‘s’:series})
print(df.asfreq(“45s”))

插值处理

从上述示例不难看出,升采样的结果会产生缺失值,那么就需要对缺失值进行处理,一般有以下几种处理方式:

方法 说明

  • pad/ffill 用前一个非缺失值去填充缺失值。
  • backfill/bfill 用后一个非缺失值去填充缺失值。
  • interpolater(‘linear’) 线性插值方法。
  • fillna(value) 指定一个值去替换缺失值。
    下面使用插值方法处理 NaN 值,示例如下:
import pandas as pd
import numpy as np
#创建时间序列数据
rng = pd.date_range('1/1/2021', periods=20, freq='3D')
ts = pd.Series(np.random.randn(len(rng)), index=rng)
print(ts.resample('D').asfreq().head())
#使用ffill处理缺失值
ts.resample('D').asfreq().ffill().head()

六.Python Pandas分类对象

通常情况下,数据集中会存在许多同一类别的信息,比如相同国家、相同行政编码、相同性别等,当这些相同类别的数据多次出现时,就会给数据处理增添许多麻烦,导致数据集变得臃肿,不能直观、清晰地展示数据。

对象创建

1) 指定dtype创建

import pandas as pd
s = pd.Series([“a”,“b”,“c”,“a”], dtype=“category”)
print(s)
通过上述示例,您可能会注意到,虽然传递给 Series 四个元素值,但是它的类别为 3,这是因为 a 的类别存在重复。

2) pd.Categorical

通过 Category 的构造函数,您可以创建一个类别对象。构造函数,如下所示:

pandas.Categorical(values, categories, ordered)

  • values:以列表的形式传参,表示要分类的值。
  • ordered:布尔值,默认为 False,若为 Ture,表示对分类的数据进行排序。
  • dtype:返回一个 category 类型,表示分类对象。
import pandas as pd
#自动按a、b、c分类
cat = pd.Categorical(['a', 'b', 'c', 'a', 'b', 'c'])
print(cat)
import pandas as pd
cat=pd.Categorical(['a','b','c','a','b','c','d'], ['c', 'b', 'a'])
print(cat)

上述示例中,第二个参数值表示类别,当列表中不存在某一类别时,会自动将类别值设置为 NA。

通过指定ordered=True来实现有序分类。示例如下:

import pandas as pd cat=pd.Categorical(['a','b','c','a','b','c','d'], ['c', 'b', 'a'],ordered=True) print(cat) #求最小值 print(cat.min())

获取统计信息

对已经分类的数据使用 describe() 方法,您会得到和数据统计相关的摘要信息。

import pandas as pd
import numpy as np
cat = pd.Categorical(["a", "c", "c", np.nan], categories=["b", "a", "c"])
df = pd.DataFrame({"cat":cat, "s":["a", "c", "c", np.nan]})
print(df.describe())
print(df["cat"].describe())

获取类别属性

使用obj.categories命令可以获取对象的类别信息。示例如下:

import pandas as pd
import numpy as np
s = pd.Categorical(["a", "c", "c", np.nan], categories=["b", "a", "c"])
print (s.categories)

通过 obj.order 可以获取 order 指定的布尔值:

import pandas as pd
import numpy as np
cat = pd.Categorical(["a", "c", "c", np.nan], categories=["b", "a", "c"])
#False表示未指定排序
print (cat.ordered)

重命名类别

要想对类别实现重命名,可以通过 Series.cat.categories 来实现的,示例如下:

import pandas as pd
s = pd.Series(["a","b","c","a"], dtype="category")
#对类名重命名
s.cat.categories = ["Group %s" % g for g in s.cat.categories]
print(s.cat.categories)

追加新类别

使用 s.cat.add_categories() 方法,可以追加新类别。

import pandas as pd
s = pd.Series(["a","b","c","a"], dtype="category")
#追加新类别
s = s.cat.add_categories([5])
#查看现有类别
print(s.cat.categories)

删除类别

使用 remove_categories() 方法,可以删除不需要的类别。示例如下:
import pandas as pd
s = pd.Series([“a”,“b”,“c”,“a”], dtype=“category”)
#原序列
print(s)
#删除后序列
print(s.cat.remove_categories(“a”))

分类对象比较

在下述两种情况下,我们可以对分类对象进行比较:

  • 当两个类别对象长度相同时,可以进行比较运算;
  • 当两个类别的 ordered 均等于 True,并且类别相同时,可以进行比较运算,比如 ==,!=,>,>=,< 和 <=。
import pandas as pd
s1=['a','a','b','d','c']
#当满足两个类别长度相同时
ss0=pd.Categorical(s1,categories=['a','d','b','c'])
ss1 = pd.Categorical(s1)
print(ss0==ss1)
s1=['a','a','b','d','c']
s2=['a','b','b','d','c']
#满足上述第二个条件,类别相同,并且ordered均为True
ss0=pd.Categorical(s1,categories=['a','d','b','c'],ordered=True)
ss1 = pd.Categorical(s2,categories=['a','d','b','c'],ordered=True)
print(ss0<ss1)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值