我们⽬前所用的累计操作都是按照⼀个维度进行,数据透视表可以看做是按照⼆维进行累计的操作功能。
# 以泰坦尼克号数据为例⼦进⾏展示
import numpy as np
import pandas as pd
import seaborn as sns
titanic = sns.load_dataset("titanic")
print(titanic.shape)
(891, 15)
先进行粗分类
a = titanic.groupby("sex")[['survived']].mean()
# 可以看出,⼥性获救⽐例⼤概是男性的4倍多
print(a)
survived
sex
female 0.742038
male 0.188908
尝试按sex,class分组,然后统计逃生人数,求mean后使用层级索引
# 可以清晰的展示出,逃⽣⼈数受sex,class 的影响
a = titanic.groupby(['sex', 'class'])['survived'].aggregate('mean').unstack()
print(a)
class First Second Third
sex
female 0.968085 0.921053 0.500000
male 0.368852 0.157407 0.135447
pivot_table实现的效果等同于上⼀节的管道命令,是⼀个简写。
# 尝试按sex,class分组,然后统计逃⽣⼈数,求mean后使⽤层级索引
a = titanic.pivot_table('survived', index='sex', columns='class')
print(a)
class First Second Third
sex
female 0.968085 0.921053 0.500000
male 0.368852 0.157407 0.135447
按照sex,age,class统计,age分三个年龄段,0-18-80
# 使⽤cut函数对年龄进⾏分段
age = pd.cut(titanic['age'], [0,18,80])
a = titanic.pivot_table('survived', ['sex', age], 'class')
print(a)
class First Second Third
sex age
female (0, 18] 0.909091 1.000000 0.511628
(18, 80] 0.972973 0.900000 0.423729
male (0, 18] 0.800000 0.600000 0.215686
(18, 80] 0.375000 0.071429 0.133663
对列也可以使用类似策略
# 使⽤qcut对票价进⾏划分成两部分,每⼀部分⼈数相等
fare = pd.qcut(titanic['fare'], 2)
a = titanic.pivot_table('survived', ['sex', age], [fare, 'class'])
print(a)
fare (-0.001, 14.454] (14.454, 512.329] \
class First Second Third First
sex age
female (0, 18] NaN 1.000000 0.714286 0.909091
(18, 80] NaN 0.880000 0.444444 0.972973
male (0, 18] NaN 0.000000 0.260870 0.800000
(18, 80] 0.0 0.098039 0.125000 0.391304
fare
class Second Third
sex age
female (0, 18] 1.000000 0.318182
(18, 80] 0.914286 0.391304
male (0, 18] 0.818182 0.178571
(18, 80] 0.030303 0.192308
数据科学的处理离不开字符串的处理,相应的pandas也提供了字符串向量化操作的功能,我们⼀般利用这个来对采集来的信息进行清理。
我们可以使用python的方式来处理字符串,但是⼀旦字符串中包含缺省值,此时,使用pandas的字符串向量化功能就能避免出现崩溃的情况。
import pandas as pd
strs = ['One', "Two", "Three", None, "Four"]
strs = pd.Series(strs)
print(strs)
0 One
1 Two
2 Three
3 None
4 Four
dtype: object
#对字符串进⾏⼤写转换
s = strs.str.upper()
print(s)
# 对字符串进⾏⼩写转换
ss = strs.str.lower()
print("\n\n", ss)
0 ONE
1 TWO
2 THREE
3 None
4 FOUR
dtype: object
0 one
1 two
2 three
3 None
4 four
dtype: object
python中字符串的方法基本上可以直接应⽤在pandas中,需要注意的是返回值的不同,需要相应做出调整,例如判断类的返回的是⼀个bool值的数据结构,len之类的返回的是⼀个值。
相应字符串方法在需要的时候可以查看手册来使用
正则是字符串的大杀器,在pandas中同样也实现了正则的⼀些接⼝,如以下API:
print("strs = \n", strs)
print()
a = strs.str.extract('([O, o, n, e, N, T ]+)')
print(a)
strs =
0 One
1 Two
2 Three
3 None
4 Four
dtype: object
0
0 One
1 T
2 T
3 NaN
4 o
pandas还提供了⼀些其他的方法来实现字符串的操作。
# 对slice的使⽤和函数的直接切⽚⼀个效果
# df.str.slice(2,5) 等于 df.str[2:5]
print("strs = \n", strs)
print()
a = strs.str.slice(1,4)
print(a)
print()
# 等价于
b = strs.str[1:4]
print(b)
strs =
0 One
1 Two
2 Three
3 None
4 Four
dtype: object
0 ne
1 wo
2 hre
3 None
4 our
dtype: object
0 ne
1 wo
2 hre
3 None
4 our
dtype: object
df.str.get(i) 和 df.str[i]功能类似
# 以下案例⽤字⺟o切分字符串后选择后⾯的⼀组
a = strs.str.split('o').str.get(-1)
print(a)
0 One
1
2 Three
3 None
4 ur
dtype: object
如果数据中包含已经倍编码的指标(coded indicator), 可以使用get_dummies快速的把编码的信息分解。
# 假定: A=游泳, B=爬⼭, C=跑步, D=篮球
df = pd.DataFrame({'english':strs,
'hobbies':["B|C", "A|C|D", "B|D", "A|B|C", "A|B|C|D"]})
print(df)
print()
a = df['hobbies'].str.get_dummies('|')
print(a)
english hobbies
0 One B|C
1 Two A|C|D
2 Three B|D
3 None A|B|C
4 Four A|B|C|D
A B C D
0 0 1 1 0
1 1 0 1 1
2 0 1 0 1
3 1 1 1 0
4 1 1 1 1
Pyhton处理时间序列常用的包有datetime,dateutil,但同样也存在性能弱的问题,pandas为了处理的⼤量时间相关数据,把时间相关数据作为datetime64类型进行处理,相对来讲,这种数据类型节省内存,处理起来速度快。
在pandas中,增加了Timestamp对象,所有日期与时间的处理方法都是通过Timestamp实现。
numpy/pandas利用Timestamp和datetime64的数据类型,将python的日期处理包datetime和dateutil有机结合
起来,可以实现对日期数据的高效灵活处理。
datetime64是numpy处理时间相关内容的数据类型,可以对时间类型数据做灵活处理,同时还可以支持各种时间单位的操作。
常见的时间单位是:
import numpy as np
# datetime64数据类型
date = np.array("20180-03-12", dtype=np.datetime64)
print(date)
20180-03-12
向量化操作
d = date + np.arange(5)
print(d)
['20180-03-12' '20180-03-13' '20180-03-14' '20180-03-15' '20180-03-16']
添加时间单位, 此处采用的是ns
a = np.datetime64("2019-01-13 12:45:32.30", "ns")
print(a)
2019-01-13T12:45:32.300000000
import pandas as pd
# 利⽤pd.to_datetime可以将多种不同的格式时间进⾏处理
date = pd.to_datetime("5th of June, 2019")
print(date)
# date可以使⽤时间格式化功能
print(date.strftime("%A"))
2019-06-05 00:00:00
Wednesday
按天计算, 进行向量化
d = date + pd.to_timedelta(np.arange(10), "D")
print(d)
DatetimeIndex(['2019-06-05', '2019-06-06', '2019-06-07', '2019-06-08',
'2019-06-09', '2019-06-10', '2019-06-11', '2019-06-12',
'2019-06-13', '2019-06-14'],
dtype='datetime64[ns]', freq=None)
idx = pd.DatetimeIndex(['2019-01-01', '2019-02-01','2019-03-01',
'2019-04-01','2019-05-01','2019-06-01'])
date = pd.Series(range(6), index=idx)
print(date)
2019-01-01 0
2019-02-01 1
2019-03-01 2
2019-04-01 3
2019-05-01 4
2019-06-01 5
dtype: int64
既然是索引,就可以使用来进行数据的提取
# 切片包含结束位置
print(date[ '2019-02-01':'2019-06-01'])
2019-02-01 1
2019-03-01 2
2019-04-01 3
2019-05-01 4
2019-06-01 5
dtype: int64
可以通过年份切片获取概念的全部数据
print(date["2019"])
2019-01-01 0
2019-02-01 1
2019-03-01 2
2019-04-01 3
2019-05-01 4
2019-06-01 5
dtype: int64
pandas对时间序列准备了几个特殊的数据结构:
pd.to_datetime传输⼀个时间日期会返回一个Timestamp类型数据
# 传递时间序列会返回DatetimeIndex类型数据
from datetime import datetime
dates = pd.to_datetime([datetime(2019,4,3), '5th of June, 2018', '2017-Jul-9',
"09-02-2018", '20190105'])
# 对⼀个时间序列,会返回DatetimeIndex类型数据
print(dates)
DatetimeIndex(['2019-04-03', '2018-06-05', '2017-07-09', '2018-09-02',
'2019-01-05'],
dtype='datetime64[ns]', freq=None)
DatetimeIndex 类型通过 pd.to_period和⼀个频率代码可以转换成PeriodIndex类型
d = dates.to_period('D')
print(d)
PeriodIndex(['2019-04-03', '2018-06-05', '2017-07-09', '2018-09-02',
'2019-01-05'],
dtype='period[D]', freq='D')
当用⼀个日期减去⼀个日期,返回的是TimedeltaIndex类型
d = dates - dates[0]
print(d)
TimedeltaIndex(['0 days', '-302 days', '-633 days', '-213 days', '-88 days'],
dtype='timedelta64[ns]', freq=None)
pandas提供了可以规律产生时间序列的函数, 此类函数的使用和range类似,pandas提供了三个函数:
d = pd.date_range("2018-03-03", "2018-12-02", periods=5)
print(d)
DatetimeIndex(['2018-03-03 00:00:00', '2018-05-10 12:00:00',
'2018-07-18 00:00:00', '2018-09-24 12:00:00',
'2018-12-02 00:00:00'],
dtype='datetime64[ns]', freq=None)
d = pd.date_range("2018-03-03", "2018-12-02", freq="M")
print(d)
DatetimeIndex(['2018-03-31', '2018-04-30', '2018-05-31', '2018-06-30',
'2018-07-31', '2018-08-31', '2018-09-30', '2018-10-31',
'2018-11-30'],
dtype='datetime64[ns]', freq='M')
d = pd.period_range("2018-01-01", periods=5, freq="M")
print(d)
PeriodIndex(['2018-01', '2018-02', '2018-03', '2018-04', '2018-05'], dtype='period[M]',
freq='M')
d = pd.timedelta_range(0, periods=5, freq="H")
print(d)
TimedeltaIndex(['00:00:00', '01:00:00', '02:00:00', '03:00:00', '04:00:00'],
dtype='timedelta64[ns]', freq='H')