pandas是建立在Numpy基础上的高效数据分析处理库,pandas提供了众多的高级函数,可以极大地简化了数据分析处理的流程。
以下为自己学习pandas的部分笔记,如有错误,欢迎指出
import numpy as np
import pandas as pd
Pandas的数据结构
pandas有三种数据结构(很快就只用两种了),分别为Series(序列),DataFrame(数据框),Panel(面板),其中panel将在0.24版本被弃用,故就不介绍了。
1、Series(序列):可以看成是具有索引的一维数组
使用pd.Series(x,index=idx):x可以为列表,一维数组,字典
第一种生成序列的方法:直接给定一个一维数组或者列表
series01 = pd.Series(np.arange(1,5))##series01 = pd.Series([1,2,3,4])
series01
0 1
1 2
2 3
3 4
dtype: int32
第二种方法:使用字典来生成序列;其中字典的keys值会直接变为序列的索引,values变为序列的数据值。
d = {'No.1':'Hajo','No.2':'Mike','No.3':'John','No.4':'Shanel'}
series02 = pd.Series(d)
series02
No.1 Hajo
No.2 Mike
No.3 John
No.4 Shanel
dtype: object
通过index和values属性可以查看序列的索引值和数据值
print('series的索引值为:\n',series01.index)
print('series的数据值为:\n',series01.values)
series的索引值为:
RangeIndex(start=0, stop=4, step=1)
series的数据值为:
[1 2 3 4]
创建序列时可以对序列的索引进行声明,亦可以在创建后在进行声明
#创建时声明索引
series03 = pd.Series(np.arange(1,6),index=['Hajo','Mike','John','Joe','Shanel'])
series03
Hajo 1
Mike 2
John 3
Joe 4
Shanel 5
dtype: int32
#创建后声明(对series01的索引声明为A,B,C,D)
print('原序列:\n',series01)
series01.index=['A','B','C','D'] ##声明的索引必须与序列的数据值的长度相等
print('改变后的序列series01:\n',series01)
原序列:
0 1
1 2
2 3
3 4
dtype: int32
改变后的序列series01:
A 1
B 2
C 3
D 4
dtype: int32
序列有一个name属性,可以通过该属性定义序列的名字
##对series02进行命名为:排名
series02.name='排名'
print('series02_name:\n',series02.name)
#创建时命名
##d = {'No.1':'Hajo','No.2':'Mike','No.3':'John','No.4':'Shanel'}
#series02 = pd.Series(d,name='排名')
series02_name:
排名
二、DataFrame(数据框):二维数据;每一行代表一个示例(instance),每一列代表一个特征(feature);可以理解为DateFrame是Series的容器。
使用pd.DataFrame(x,index=idx,columns=col),x:二维列表,二维数组,字典(其值是一维列表,numpy数组或者Series),另一个DataFrame;index:行索引;columns:列索引
第一种方法:使用numpy数组或二维列表
#df01 = pd.DataFrame([[1,2,3,4],[6,7,8,9]])
df01 = pd.DataFrame(np.array([[1,2,3,4],[6,7,8,9]]))
df01
0 | 1 | 2 | 3 | |
---|---|---|---|---|
0 | 1 | 2 | 3 | 4 |
1 | 6 | 7 | 8 | 9 |
第二种方法:使用字典(对象为一维列表);字典的keys值变为columns索引,values变为columns的值
indexs = ['Hajo','Mike','John','Joe','Shanel']
date = {'gender':['male','male','male','female','female'],
'score':[89,87,95,93,99]}
df2 = pd.DataFrame(date,index=indexs)
df2.index.name='name'
df2.columns.name='分割'
df2
分割 | gender | score |
---|---|---|
name | ||
Hajo | male | 89 |
Mike | male | 87 |
John | male | 95 |
Joe | female | 93 |
Shanel | female | 99 |
##将index中的名字改变为A,B,C,D,E
df2.index=['A','B','C','D','E'] ##只能整体改变,不可以只改变一个
df2
分割 | gender | score |
---|---|---|
A | male | 89 |
B | male | 87 |
C | male | 95 |
D | female | 93 |
E | female | 99 |
DataFrame的部分属性:df.shape,df.index,df.values,df.columns
print('df2的部分属性:\n')
print('df2的形状:\n',df2.shape)
print('df2的index:\n',df2.index)
print('df2的values:\n',df2.values)
print('df2的columns:\n',df2.columns)
df2的部分属性:
df2的形状:
(5, 2)
df2的index:
Index(['A', 'B', 'C', 'D', 'E'], dtype='object')
df2的values:
[['male' 89]
['male' 87]
['male' 95]
['female' 93]
['female' 99]]
df2的columns:
Index(['gender', 'score'], dtype='object', name='分割')
查看DataFrame:通过df.head(n),df.tail(n)可以从头部或尾部查看DataFrame的n行,n默认为5
df2.head(3)
分割 | gender | score |
---|---|---|
A | male | 89 |
B | male | 87 |
C | male | 95 |
df2.tail(3)
分割 | gender | score |
---|---|---|
C | male | 95 |
D | female | 93 |
E | female | 99 |
统计DataFrame:使用df.describe()
df2.describe()
分割 | score |
---|---|
count | 5.000000 |
mean | 92.600000 |
std | 4.774935 |
min | 87.000000 |
25% | 89.000000 |
50% | 93.000000 |
75% | 95.000000 |
max | 99.000000 |
数据框的索引和切片
Series的索引和切片与numpy数组的类似,所以主要学习DataFrame的索引和切片
DataFrame的索引和切片可以基于标签,也可以基于位置,不像numpy数组只能基于位置;所以DataFrame的索引和切片有四大类:a、索引单元素;b、切片columns;c、切片index;d、切片columns和index
a、索引单元素:基于标签的at;基于位置的iat;
b、切片columns:用 . 来切片单列;用[]来切片单列或多列;基于标签的loc;基于位置的iloc;
c、切片index:用[]来切片单列或多列;基于标签的loc;基于位置的iloc;
d、切片columns和index:基于标签的loc,基于位置的iloc
总的来说,主要有两种使用:基于标签的at、loc;基于位置的iat、iloc;其实在最后使用时,一般我们使用的都会是loc或者iloc
symbol = ['BABA','JD','APPL','MS','GS','WMT']
data1 = {'行业':['电商','电商','科技','金融','金融','零售'],
'价格':[176.92,25.95,172.97,41.79,196.00,99.55],
'交易量':[16175612,27113297,19856335,10151252,12553515,8086946],
'雇员':[101550,175336,100000,60348,36600,220000]}
df02 = pd.DataFrame(data1,index=symbol)
df02.name='美股'
df02.index.name='代号'
df02
行业 | 价格 | 交易量 | 雇员 | |
---|---|---|---|---|
代号 | ||||
BABA | 电商 | 176.92 | 16175612 | 101550 |
JD | 电商 | 25.95 | 27113297 | 175336 |
APPL | 科技 | 172.97 | 19856335 | 100000 |
MS | 金融 | 41.79 | 10151252 | 60348 |
GS | 金融 | 196.00 | 12553515 | 36600 |
WMT | 零售 | 99.55 | 8086946 | 220000 |
a、索引单元素—只举例at和iat
##获取苹果公司的价格
APPL_Price1 = df02.at['APPL','价格']
APPL_Price2 = df02.iat[2,1]
print('基于标签:',APPL_Price1)
print('基于位置:',APPL_Price2)
基于标签: 172.97
基于位置: 172.97
b、切片columns–只举例loc和iloc
##获取价格这一列
col_Price = df02.loc[:,'价格']
col_Price1 = df02.iloc[:,1]
print('基于标签:\n',col_Price)
print('介于位置:\n',col_Price1)
基于标签:
代号
BABA 176.92
JD 25.95
APPL 172.97
MS 41.79
GS 196.00
WMT 99.55
Name: 价格, dtype: float64
介于位置:
代号
BABA 176.92
JD 25.95
APPL 172.97
MS 41.79
GS 196.00
WMT 99.55
Name: 价格, dtype: float64
c、切片index
##获取京东的整个信息
JD_info = df02.loc['JD',:]
JD_info1 = df02.iloc[1,:]
print('基于标签:\n',JD_info)
print('基于位置:\n',JD_info1)
基于标签:
行业 电商
价格 25.95
交易量 27113297
雇员 175336
Name: JD, dtype: object
基于位置:
行业 电商
价格 25.95
交易量 27113297
雇员 175336
Name: JD, dtype: object
d、切片index和columns:这一种其实就是上面两种的结合,不同的是上面两种要么获取整行,要么获取整列,所以可以这样认为上面两种就是第四种方法的特类
##获取BABA,JD,APPL的价格和交易量
info = df02.loc[['BABA','JD','APPL'],['价格','交易量']]
info1 = df02.iloc[0:3,1:3]
print('基于标签:\n',info)
print('基于位置:\n',info1)
基于标签:
价格 交易量
代号
BABA 176.92 16175612
JD 25.95 27113297
APPL 172.97 19856335
基于位置:
价格 交易量
代号
BABA 176.92 16175612
JD 25.95 27113297
APPL 172.97 19856335
高级索引:布尔索引
##筛选雇员大于100000的公司
print(df02.雇员>=100000)
df02.loc[df02.雇员 >= 100000,:]
代号
BABA True
JD True
APPL True
MS False
GS False
WMT True
Name: 雇员, dtype: bool
行业 | 价格 | 交易量 | 雇员 | |
---|---|---|---|---|
代号 | ||||
BABA | 电商 | 176.92 | 16175612 | 101550 |
JD | 电商 | 25.95 | 27113297 | 175336 |
APPL | 科技 | 172.97 | 19856335 | 100000 |
WMT | 零售 | 99.55 | 8086946 | 220000 |
多个筛选条件可以使用逻辑运算符:&,|;需要注意运算的优先级–使用括号()
##筛选价格大于150,雇员小于100000的公司
df02.loc[(df02.价格>150)&(df02.雇员<100000),:]
行业 | 价格 | 交易量 | 雇员 | |
---|---|---|---|---|
代号 | ||||
GS | 金融 | 196.0 | 12553515 | 36600 |
数据表的合并与连接
数据表可以按‘键’合并,用merge函数;也可以按‘轴’连接,使用concat函数。
按键合并
merge函数,用法:pd.merge(df1,df2,how=‘inner’,on=c,suffixes=[]);
参数how:是使用合并方式,四种:
inner(默认)–>合并所有行即将两个数据表的行索引全部显示相当于并集,
outer–>合并df1和df2共有的行即相当于交集,
left–>连接后显示左边df1的所有行即保留df2中df1有的行,去除df2中df1没有的;
right–>连接后保留右边df2中所有的行即保留df1中df2有的,去除df1中df2没有的。
参数on:df1和df2共有的一栏或者多栏,所以跟c的栏数即列名columns_name,又分为单键合并和多键合并。
参数suffixes:设置后缀名,
后缀名的产生:当合并时,两个df除了合并的键,还有其他具有相同名称(列名)的键时,就会产生,默认是加上’_x,_y’
##创建两个DataFrame
d_left = {'Date':pd.date_range('2019-1-1',periods=4),
'temperate':[17.3,18.6,17.2,18]}
df_left = pd.DataFrame(d_left)
df_left
Date | temperate | |
---|---|---|
0 | 2019-01-01 | 17.3 |
1 | 2019-01-02 | 18.6 |
2 | 2019-01-03 | 17.2 |
3 | 2019-01-04 | 18.0 |
d_right = {'Date':pd.date_range('2019-1-3',periods=4),
'weather':['good','good','bad','good']}
df_right = pd.DataFrame(d_right)
df_right
Date | weather | |
---|---|---|
0 | 2019-01-03 | good |
1 | 2019-01-04 | good |
2 | 2019-01-05 | bad |
3 | 2019-01-06 | good |
##根据Date中的值来合并
##默认内链接inner
inner_df = pd.merge(df_left,df_right,how='inner',on=['Date'])
print('内连接:\n',inner_df)
##外连接outer
outer_df = pd.merge(df_left,df_right,how='outer',on=['Date'])
print('外连接:\n',outer_df)
##左连接left join
left_df = pd.merge(df_left,df_right,how='left')
print('左连接:\n',left_df)
##右连接 right join
right_df = pd.merge(df_left,df_right,how='right')
print('右连接:\n',right_df)
内连接:
Date temperate weather
0 2019-01-03 17.2 good
1 2019-01-04 18.0 good
外连接:
Date temperate weather
0 2019-01-01 17.3 NaN
1 2019-01-02 18.6 NaN
2 2019-01-03 17.2 good
3 2019-01-04 18.0 good
4 2019-01-05 NaN bad
5 2019-01-06 NaN good
左连接:
Date temperate weather
0 2019-01-01 17.3 NaN
1 2019-01-02 18.6 NaN
2 2019-01-03 17.2 good
3 2019-01-04 18.0 good
右连接:
Date temperate weather
0 2019-01-03 17.2 good
1 2019-01-04 18.0 good
2 2019-01-05 NaN bad
3 2019-01-06 NaN good
以上的是单键合并,下面举个多键合并的例子:
##创建两个df
df_left1 = pd.DataFrame({'Date':pd.date_range('2019-1-1',periods=4),
'temperate':[20,21,22,23],
'weather':['good','bad','bad','bad']})
df_left1
Date | temperate | weather | |
---|---|---|---|
0 | 2019-01-01 | 20 | good |
1 | 2019-01-02 | 21 | bad |
2 | 2019-01-03 | 22 | bad |
3 | 2019-01-04 | 23 | bad |
df_right1 = pd.DataFrame({'Date':pd.date_range('2019-1-3',periods=4),
'temperate':[18,17,16,15],
'weather':['bad','good','good','bad']})
df_right1
Date | temperate | weather | |
---|---|---|---|
0 | 2019-01-03 | 18 | bad |
1 | 2019-01-04 | 17 | good |
2 | 2019-01-05 | 16 | good |
3 | 2019-01-06 | 15 | bad |
在Date和temperate两个键上做外合并
##多键外合并
l_df = pd.merge(df_left1,df_right1,how='outer',on=['Date','temperate'])
l_df
Date | temperate | weather_x | weather_y | |
---|---|---|---|---|
0 | 2019-01-01 | 20 | good | NaN |
1 | 2019-01-02 | 21 | bad | NaN |
2 | 2019-01-03 | 22 | bad | NaN |
3 | 2019-01-04 | 23 | bad | NaN |
4 | 2019-01-03 | 18 | NaN | bad |
5 | 2019-01-04 | 17 | NaN | good |
6 | 2019-01-05 | 16 | NaN | good |
7 | 2019-01-06 | 15 | NaN | bad |
##添加后缀名
l_df = pd.merge(df_left1,df_right1,how='outer',on=['Date','temperate'],suffixes=['_left','_right'])
l_df
Date | temperate | weather_left | weather_right | |
---|---|---|---|---|
0 | 2019-01-01 | 20 | good | NaN |
1 | 2019-01-02 | 21 | bad | NaN |
2 | 2019-01-03 | 22 | bad | NaN |
3 | 2019-01-04 | 23 | bad | NaN |
4 | 2019-01-03 | 18 | NaN | bad |
5 | 2019-01-04 | 17 | NaN | good |
6 | 2019-01-05 | 16 | NaN | good |
7 | 2019-01-06 | 15 | NaN | bad |
按轴连接
Series和DataFrame相互连接,使用pd.concat函数
用法:pd.concat([s1,s2,s3…],axis=0)或者pd.concat([df1,df2,df3,…],axis=0)
Series连接时:axis=0,会得到更长的Series;axis=1,则会变成一个DataFrame.
###使用pd.concat()连接三个Series
s1 = pd.Series([0,1],index=['a','b'])
s2 = pd.Series([2,3],index=['c','d'])
s3 = pd.Series([4,5],index=['e','f'])
pd.concat([s1,s2,s3],axis=0)
a 0
b 1
c 2
d 3
e 4
f 5
dtype: int64
pd.concat([s1,s2,s3],axis=1,sort='True')
0 | 1 | 2 | |
---|---|---|---|
a | 0.0 | NaN | NaN |
b | 1.0 | NaN | NaN |
c | NaN | 2.0 | NaN |
d | NaN | 3.0 | NaN |
e | NaN | NaN | 4.0 |
f | NaN | NaN | 5.0 |
##使用pd.concat()连接两个DateFrame
df1 = pd.DataFrame({'name':['Hajo','Mike'],
'gender':['female','female'],
'age':[21,22]})
df2 = pd.DataFrame({'name':['Joe','Shanel'],
'gender':['male','male'],
'age':[20,21]})
pd.concat([df1,df2],axis=0)
name | gender | age | |
---|---|---|---|
0 | Hajo | female | 21 |
1 | Mike | female | 22 |
0 | Joe | male | 20 |
1 | Shanel | male | 21 |
pd.concat([df1,df2],axis=1)
name | gender | age | name | gender | age | |
---|---|---|---|---|---|---|
0 | Hajo | female | 21 | Joe | male | 20 |
1 | Mike | female | 22 | Shanel | male | 21 |
数据表的重塑和透视
重塑(reshape)和透视(pivot)两个操作只改变数据表的布局(layout):
·重塑用stack和unstack函数(互为逆转操作)
·透视用pivot和melt函数(互为逆转操作)
重塑
重塑:简单点理解就是行索引与列索引的相互转换,从而来改变数据表的展示形式。
·列索引➡行索引,用stack函数
·行索引➡列索引,用unstack函数
name_symbol = ['Hajo','Shanel']
info_data = {'行业':['IT','金融'],
'年龄':[23,22],
'工资':[15000,9000]}
person_df = pd.DataFrame(info_data,index=name_symbol)
person_df.columns.name = '信息类别'
person_df.index.name = '姓名'
person_df
信息类别 | 行业 | 年龄 | 工资 |
---|---|---|---|
姓名 | |||
Hajo | IT | 23 | 15000 |
Shanel | 金融 | 22 | 9000 |
stack:列索引➡行索引
原来的DataFrame person_df 变成两层Series(第一层索引为姓名,第二层索引为信息类别)
c2i_Series = person_df.stack()
c2i_Series
姓名 信息类别
Hajo 行业 IT
年龄 23
工资 15000
Shanel 行业 金融
年龄 22
工资 9000
dtype: object
unstack:行索引➡列索引
原来的DateFrame person_df 也变成两层Series(第一层索引为信息类别,第二层索引为姓名)
i2c_Series = person_df.unstack()
i2c_Series
信息类别 姓名
行业 Hajo IT
Shanel 金融
年龄 Hajo 23
Shanel 22
工资 Hajo 15000
Shanel 9000
dtype: object
从上面可以发现:stack其实是将DataFrame,重新按index进行分类显示
unstack则是将DataFrame,重新按columns进行分类显示。
这只是对于单层DataFrame来说,也是我的理解,其实对于多层DataFrame也差不多,只不过要考虑到想按那一层索引来分类而已。
透视
Pandas里透视的方法有两种:
·用pivot函数将‘一张长表’变‘多张宽表’;
·用melt函数将‘多张宽表’变‘一张长表’本次使用数据是5只股票(AAPL,JD,BABA,FB,GS)4个交易日(2019-02-21 to 2019-02-26)的交易信息(数据来源:微信公众号:【王的机器】,顺便说下,这个公众号挺好的,有很多关于量化交易,数据分析和机器学习等方面的文章,需要的可以关注哦),文末有链接下载!!!
data = pd.read_csv('Stock.csv',parse_dates=[0],dayfirst=True)
##结果为20行,这里只显示前5行和后5行
data.head().append(data.tail())
Date | Symbol | Open | High | Low | Close | Adj Close | Volume | |
---|---|---|---|---|---|---|---|---|
0 | 2019-02-21 | AAPL | 171.800003 | 172.369995 | 170.300003 | 171.059998 | 171.059998 | 17249700 |
1 | 2019-02-21 | JD | 24.820000 | 24.879999 | 24.010000 | 24.270000 | 24.270000 | 13542600 |
2 | 2019-02-21 | BABA | 171.000000 | 171.779999 | 169.800003 | 171.660004 | 171.660004 | 8434800 |
3 | 2019-02-21 | GS | 198.970001 | 199.449997 | 195.050003 | 196.360001 | 196.360001 | 2785900 |
4 | 2019-02-21 | FB | 161.929993 | 162.240005 | 159.589996 | 160.039993 | 160.039993 | 15607800 |
15 | 2019-02-26 | AAPL | 173.710007 | 175.300003 | 173.169998 | 174.330002 | 174.330002 | 17006000 |
16 | 2019-02-26 | JD | 25.980000 | 26.820000 | 25.660000 | 26.590000 | 26.590000 | 20264100 |
17 | 2019-02-26 | BABA | 179.789993 | 184.350006 | 179.369995 | 183.539993 | 183.539993 | 13857900 |
18 | 2019-02-26 | GS | 198.470001 | 200.559998 | 196.550003 | 198.899994 | 198.899994 | 2498000 |
19 | 2019-02-26 | FB | 164.339996 | 166.240005 | 163.800003 | 164.130005 | 164.130005 | 13645200 |
从长到宽:df.pivot()
pivot函数会将原始的数据表透视成一个新的数据表,故主要的语法可以这样理解:
df.pivot(index=[],columns=’’,values=[])
index:新数据表的行索引,可以不设置,默认是数字索引,也可从把原始数据表中一个columns当成index;
columns:新数据表的列索引,与index的设置一样,从原始数据表中指定一个。
values:新数据表的值,从原始数据表中指定需要查看的一个或多个标签(一般是columns),如果不指定,则会显示除了被设置为index和columns的所有原始数据表的columns
"""
将index设置为date,
将columns设置为symbol,
将values指定为Adj Close
"""
close_df = data.pivot(index = 'Date',
columns = 'Symbol',
values = 'Adj Close')
close_df
Symbol | AAPL | BABA | FB | GS | JD |
---|---|---|---|---|---|
Date | |||||
2019-02-21 | 171.059998 | 171.660004 | 160.039993 | 196.360001 | 24.270000 |
2019-02-22 | 172.970001 | 176.919998 | 161.889999 | 196.000000 | 25.950001 |
2019-02-25 | 174.229996 | 183.250000 | 164.619995 | 198.649994 | 26.190001 |
2019-02-26 | 174.330002 | 183.539993 | 164.130005 | 198.899994 | 26.590000 |
##将values指定为Adj Close,Open,Volume,来查看多个内容
data.pivot(index = 'Date',
columns = 'Symbol',
values = ['Adj Close','Open','Volume'])
Adj Close | Open | Volume | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Symbol | AAPL | BABA | FB | GS | JD | AAPL | BABA | FB | GS | JD | AAPL | BABA | FB | GS | JD |
Date | |||||||||||||||
2019-02-21 | 171.059998 | 171.660004 | 160.039993 | 196.360001 | 24.270000 | 171.800003 | 171.000000 | 161.929993 | 198.970001 | 24.820000 | 17249700.0 | 8434800.0 | 15607800.0 | 2785900.0 | 13542600.0 |
2019-02-22 | 172.970001 | 176.919998 | 161.889999 | 196.000000 | 25.950001 | 171.580002 | 172.800003 | 160.580002 | 196.600006 | 24.549999 | 18913200.0 | 16175600.0 | 15858500.0 | 2626600.0 | 27113300.0 |
2019-02-25 | 174.229996 | 183.250000 | 164.619995 | 198.649994 | 26.190001 | 174.160004 | 181.259995 | 163.070007 | 198.000000 | 27.110001 | 21873400.0 | 22831800.0 | 18737100.0 | 3032200.0 | 29338500.0 |
2019-02-26 | 174.330002 | 183.539993 | 164.130005 | 198.899994 | 26.590000 | 173.710007 | 179.789993 | 164.339996 | 198.470001 | 25.980000 | 17006000.0 | 13857900.0 | 13645200.0 | 2498000.0 | 20264100.0 |
##不设置values
all_pivot = data.pivot(index = "Date",
columns = "Symbol")
all_pivot
Open | High | ... | Adj Close | Volume | |||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Symbol | AAPL | BABA | FB | GS | JD | AAPL | BABA | FB | GS | JD | ... | AAPL | BABA | FB | GS | JD | AAPL | BABA | FB | GS | JD |
Date | |||||||||||||||||||||
2019-02-21 | 171.800003 | 171.000000 | 161.929993 | 198.970001 | 24.820000 | 172.369995 | 171.779999 | 162.240005 | 199.449997 | 24.879999 | ... | 171.059998 | 171.660004 | 160.039993 | 196.360001 | 24.270000 | 17249700 | 8434800 | 15607800 | 2785900 | 13542600 |
2019-02-22 | 171.580002 | 172.800003 | 160.580002 | 196.600006 | 24.549999 | 173.000000 | 177.020004 | 162.410004 | 197.750000 | 25.959999 | ... | 172.970001 | 176.919998 | 161.889999 | 196.000000 | 25.950001 | 18913200 | 16175600 | 15858500 | 2626600 | 27113300 |
2019-02-25 | 174.160004 | 181.259995 | 163.070007 | 198.000000 | 27.110001 | 175.869995 | 183.720001 | 166.070007 | 201.500000 | 27.379999 | ... | 174.229996 | 183.250000 | 164.619995 | 198.649994 | 26.190001 | 21873400 | 22831800 | 18737100 | 3032200 | 29338500 |
2019-02-26 | 173.710007 | 179.789993 | 164.339996 | 198.470001 | 25.980000 | 175.300003 | 184.350006 | 166.240005 | 200.559998 | 26.820000 | ... | 174.330002 | 183.539993 | 164.130005 | 198.899994 | 26.590000 | 17006000 | 13857900 | 13645200 | 2498000 | 20264100 |
4 rows × 30 columns
从宽到长: pd.melt()
pd.melt(DataFrame,id_vars=[],value_vars=[],var_name=’’,value_name=’’)
·id_vars:id–>可以这样理解为id不是分类索引
·value_vars:variable–>理解为是分类索引
·var_name:分类索引的列名,默认是variable
·value_name:对应于原始数据表中分类索引的对应值的列名
***** var_name和value_name参数说的很拗口,看第二个例子就会理解了
具体来说,函数 melt 实际是将「源表」转化成 id-variable 类型的 DataFrame,下例将
·Date 和 Symbol 列当成 id
·其他列 Open, High, Low, Close, Adj Close 和 Volume 当成 variable,而它们对应的值当成 value
melted_data = pd.melt(data,id_vars=['Date','Symbol'])
##显示前5行和后5行
melted_data.head(5).append(melted_data.tail(5))
Date | Symbol | variable | value | |
---|---|---|---|---|
0 | 2019-02-21 | AAPL | Open | 1.718000e+02 |
1 | 2019-02-21 | JD | Open | 2.482000e+01 |
2 | 2019-02-21 | BABA | Open | 1.710000e+02 |
3 | 2019-02-21 | GS | Open | 1.989700e+02 |
4 | 2019-02-21 | FB | Open | 1.619300e+02 |
115 | 2019-02-26 | AAPL | Volume | 1.700600e+07 |
116 | 2019-02-26 | JD | Volume | 2.026410e+07 |
117 | 2019-02-26 | BABA | Volume | 1.385790e+07 |
118 | 2019-02-26 | GS | Volume | 2.498000e+06 |
119 | 2019-02-26 | FB | Volume | 1.364520e+07 |
##设置var_name和value_name
pd.melt(data,id_vars=['Date','Symbol'],var_name='分类类别',value_name='对应值').head()
Date | Symbol | 分类类别 | 对应值 | |
---|---|---|---|---|
0 | 2019-02-21 | AAPL | Open | 171.800003 |
1 | 2019-02-21 | JD | Open | 24.820000 |
2 | 2019-02-21 | BABA | Open | 171.000000 |
3 | 2019-02-21 | GS | Open | 198.970001 |
4 | 2019-02-21 | FB | Open | 161.929993 |
对于透视:其实可以理解为将需要查看的属性分类出来,便于我们的理解。
数据表的分组和整合
DataFrame 中的数据可以根据某些规则分组,然后在每组的数据上计算出不同统计量。这种操作称之为 split-apply-combine,简单理解就是:我们先将数据表按各种标签分组,再通过运算操作,将各个标签的内容进行分析,最后再整合成需要的数据表。由于不需要太多数据,需要处理一下数据,保留数据中的’Date’,Symbol’和’Adj Close’
##读取数据并进行数据处理:
data = pd.read_csv('1Y_Stock_Data.csv',parse_dates=[0],dayfirst=True)
data = data[['Date','Symbol','Adj Close']]
data.insert(1,'Year',pd.DatetimeIndex(data['Date']).year)
data.insert(2,'Month',pd.DatetimeIndex(data['Date']).month)
data.head(3).append(data.tail(3))
Date | Year | Month | Symbol | Adj Close | |
---|---|---|---|---|---|
0 | 2018-02-26 | 2018 | 2 | AAPL | 176.285675 |
1 | 2018-02-27 | 2018 | 2 | AAPL | 175.714386 |
2 | 2018-02-28 | 2018 | 2 | AAPL | 175.448410 |
1257 | 2019-02-22 | 2019 | 2 | GS | 196.000000 |
1258 | 2019-02-25 | 2019 | 2 | GS | 198.649994 |
1259 | 2019-02-26 | 2019 | 2 | GS | 198.899994 |
分组(grouping)
用一组特定标签(label)将数据(data)进行分组:
data.groupby(label)
返回的是一个DataFrameGroupBy类型,有以下部分属性和方法:
·ngroups:组的个数(int)
·size():每组元素的个数(Series)
·groups:每组元素在原DataFrame中的索引信息(dict)
·get_groups(label):标签label对应的数据(DataFrame)
##定义一个print_groups函数来打印组的名字和前5行信息:
def print_groups(group_ojb):
for name,group in group_ojb:
print(name)
print(group.head())
##单标签分组
grouped = data.groupby('Symbol')
print_groups(grouped)
AAPL
Date Year Month Symbol Adj Close
0 2018-02-26 2018 2 AAPL 176.285675
1 2018-02-27 2018 2 AAPL 175.714386
2 2018-02-28 2018 2 AAPL 175.448410
3 2018-03-01 2018 3 AAPL 172.375214
4 2018-03-02 2018 3 AAPL 173.567078
BABA
Date Year Month Symbol Adj Close
252 2018-02-26 2018 2 BABA 194.190002
253 2018-02-27 2018 2 BABA 188.259995
254 2018-02-28 2018 2 BABA 186.139999
255 2018-03-01 2018 3 BABA 181.990005
256 2018-03-02 2018 3 BABA 179.759995
FB
Date Year Month Symbol Adj Close
756 2018-02-26 2018 2 FB 184.929993
757 2018-02-27 2018 2 FB 181.460007
758 2018-02-28 2018 2 FB 178.320007
759 2018-03-01 2018 3 FB 175.940002
760 2018-03-02 2018 3 FB 176.619995
GS
Date Year Month Symbol Adj Close
1008 2018-02-26 2018 2 GS 267.574249
1009 2018-02-27 2018 2 GS 264.289459
1010 2018-02-28 2018 2 GS 260.085419
1011 2018-03-01 2018 3 GS 254.001984
1012 2018-03-02 2018 3 GS 255.327515
JD
Date Year Month Symbol Adj Close
504 2018-02-26 2018 2 JD 48.799999
505 2018-02-27 2018 2 JD 47.040001
506 2018-02-28 2018 2 JD 47.150002
507 2018-03-01 2018 3 JD 46.209999
508 2018-03-02 2018 3 JD 43.799999
##多标签分组
grouped2 = data.groupby(['Symbol','Year','Month'])
#print_groups(grouped2)
整合(aggregating)
##用mean()函数计算每个Symbol下一年的股价均值
grouped.mean()
Year | Month | Adj Close | |
---|---|---|---|
Symbol | |||
AAPL | 2018.150794 | 6.488095 | 186.022309 |
BABA | 2018.150794 | 6.488095 | 171.780992 |
FB | 2018.150794 | 6.488095 | 167.244841 |
GS | 2018.150794 | 6.488095 | 221.593412 |
JD | 2018.150794 | 6.488095 | 31.340754 |
##使用内置函数agg()作用到组对象上
result = grouped.agg(lambda x :np.max(x)-np.min(x))
result.head().append(result.tail())
Date | Year | Month | Adj Close | |
---|---|---|---|---|
Symbol | ||||
AAPL | 365 days | 1 | 11 | 88.692703 |
BABA | 365 days | 1 | 11 | 80.259995 |
FB | 365 days | 1 | 11 | 93.440002 |
GS | 365 days | 1 | 11 | 114.072418 |
JD | 365 days | 1 | 11 | 29.529999 |
AAPL | 365 days | 1 | 11 | 88.692703 |
BABA | 365 days | 1 | 11 | 80.259995 |
FB | 365 days | 1 | 11 | 93.440002 |
GS | 365 days | 1 | 11 | 114.072418 |
JD | 365 days | 1 | 11 | 29.529999 |
Pandas文件读取与存储
跟numpy库一样。pandas库也提供了文件的读取和存储,而我们一般也是使用pandas的这一部分来对文件进行读取的 pandas支持对多种文件的读取和存储如:csv文件,json文件,excel文件,hdf文件(一种二进制文件格式),这里主要讲csv文件的操作,也是我们最常用的文件操作。读取语法:
pd.read_csv(path,usecols=[],names=[],index_col=[],encoding=’’)
- path:文件路径
- usecols:针对有表头文件,需要的字段
- names:针对无表头文件,需要的表头字段
- index_col:将某列设置为index
- encoding:编码格式
存储语法:
df.to_csv(path,columns,mode=‘w’,index=False,header=False,encoding=’’) - path:文件存储路径
- columns:列名
- mode:存储模式,‘w’–>重写;‘a’–>追加
- index;是否加入行索引,默认False
- header:是否添加表头,默认False
- encoding:编码格式(这里说下,如果你使用’utf_8’后中文依旧是乱码,请改为’utf_8_sig’)
##对person_df进行操作
person_df
信息类别 | 行业 | 年龄 | 工资 |
---|---|---|---|
姓名 | |||
Hajo | IT | 23 | 15000 |
Shanel | 金融 | 22 | 9000 |
##存储到当前目录下,并命名为info.csv
person_df.to_csv('info.csv',encoding='utf_8_sig')
##读取出info.csv
person_df2 = pd.read_csv('info.csv',index_col=['姓名'])
person_df2
行业 | 年龄 | 工资 | |
---|---|---|---|
姓名 | |||
Hajo | IT | 23 | 15000 |
Shanel | 金融 | 22 | 9000 |
#################################################################################
以上就是pandas的一些基本操作,主要用于对数据的分析为主。
下面的是利用pandas对数据进行预处理的一些操作笔记。(可能例子会少一些)
DataFrame运算
1、算术运算:
- 使用运算符;
- 使用运算方法如df.add(other_df),df.sub(other_df)
2、逻辑运算:
- 运算符:<,>,|,&,<=,>=
- bool索引:类似于data[data[‘high’]>15]
- 组合逻辑:(需要注意优先级)
例如:data[(data[‘high’]>15)&(data[‘low’]<15)]
使用query()方法:data.query(‘high>15&low<15’) 与上式相同结果
使用isin()方法:判断data中turnover是否含有4.19,4.39–>data[data[‘turnover’].isin(4.19,4.39)]
3、统计运算:
- 使用max,min,mean,median,var,std依次返回常见的指标:最大值,最小值,均值,中位数,方差,标准差
- data.describe()–>直接返回上面的指标
4、自定义运算;
- 使用apply()函数,其语法:
apply(func,axis=0)
func:自定义函数
axis:作用的方向,默认是列即axis=0,axis=1–>行
data = pd.read_csv('Stock.csv')
data.head()
Date | Symbol | Open | High | Low | Close | Adj Close | Volume | |
---|---|---|---|---|---|---|---|---|
0 | 21/02/2019 | AAPL | 171.800003 | 172.369995 | 170.300003 | 171.059998 | 171.059998 | 17249700 |
1 | 21/02/2019 | JD | 24.820000 | 24.879999 | 24.010000 | 24.270000 | 24.270000 | 13542600 |
2 | 21/02/2019 | BABA | 171.000000 | 171.779999 | 169.800003 | 171.660004 | 171.660004 | 8434800 |
3 | 21/02/2019 | GS | 198.970001 | 199.449997 | 195.050003 | 196.360001 | 196.360001 | 2785900 |
4 | 21/02/2019 | FB | 161.929993 | 162.240005 | 159.589996 | 160.039993 | 160.039993 | 15607800 |
##提取data中的Open列,并全部加上10
data_open = data['Open']
data_open = data_open + 10
##data_open = data_open.add(10)
data_open.head()
0 181.800003
1 34.820000
2 181.000000
3 208.970001
4 171.929993
Name: Open, dtype: float64
##筛选出Symbol为DJ,且High小于25的所有内容
data[(data['Symbol']=='JD')&(data['High']<25)]
Date | Symbol | Open | High | Low | Close | Adj Close | Volume | |
---|---|---|---|---|---|---|---|---|
1 | 21/02/2019 | JD | 24.82 | 24.879999 | 24.01 | 24.27 | 24.27 | 13542600 |
##查看dat所有常见指标
data.describe()
Open | High | Low | Close | Adj Close | Volume | |
---|---|---|---|---|---|---|
count | 20.000000 | 20.000000 | 20.000000 | 20.000000 | 20.000000 | 2.000000e+01 |
mean | 147.026001 | 148.733501 | 146.126000 | 147.577499 | 147.577499 | 1.506961e+07 |
std | 63.444844 | 64.005651 | 63.208793 | 63.615368 | 63.615368 | 7.879190e+06 |
min | 24.549999 | 24.879999 | 24.010000 | 24.270000 | 24.270000 | 2.498000e+06 |
25% | 161.592495 | 162.367504 | 160.129998 | 161.427497 | 161.427497 | 1.226565e+07 |
50% | 171.690002 | 172.684998 | 170.840004 | 172.315002 | 172.315002 | 1.601705e+07 |
75% | 180.157493 | 183.877502 | 179.709995 | 183.322498 | 183.322498 | 1.925092e+07 |
max | 198.970001 | 201.500000 | 197.710007 | 198.899994 | 198.899994 | 2.933850e+07 |
##使用apply()函数提取出所有列中的最大值
data_cols = data.iloc[:,2:]
data_cols.apply(lambda x : np.max(x))
Open 1.989700e+02
High 2.015000e+02
Low 1.977100e+02
Close 1.989000e+02
Adj Close 1.989000e+02
Volume 2.933850e+07
dtype: float64
缺失值处理
有时候我们得到文件可能会存在部分的缺失值,这时就得对这些缺失值进行处理,从而减少由于缺失值而带来的误差:
常见的思路有两种:
a、样本数据足够多时,可以选择直接删除缺失值
b、样本数据不足时,使用插补法进行处理(使用该列的均值,中位数等)NaN类型处理流程:
1,判断数据中是否有缺失值(NaN):
pd.isnull(df)–>是NaN,标记为True;
pd.notnull(df)–>是NaN,标记为False;
2,处理缺失值:
a、直接删除:
df.dropna(axis=1),默认按行删除即axis=1
b、替换/插补:
df.fillna(value,inplace=False)–>value:填补的值
inplace:是否就地填补即在原数据中进行填补,默认False非NaN类型的处理流程则需先将该标记(?,空格,等特殊符号)转换为NaN类型,在进行上述的处理。
处理函数:
df.replace(to_replace=’’,value=),to_replace:被替换内容,value:替换值,一般为np.nan
##提取data中Date为2019-02-21这天5只股票股市情况,并将部分值设为?
data_Date = data[data['Date']=='21/02/2019']
data_Date.iloc[1,3]='?'
data_Date.iloc[1,4]='?'
data_Date
Date | Symbol | Open | High | Low | Close | Adj Close | Volume | |
---|---|---|---|---|---|---|---|---|
0 | 21/02/2019 | AAPL | 171.800003 | 172.37 | 170.3 | 171.059998 | 171.059998 | 17249700 |
1 | 21/02/2019 | JD | 24.820000 | ? | ? | 24.270000 | 24.270000 | 13542600 |
2 | 21/02/2019 | BABA | 171.000000 | 171.78 | 169.8 | 171.660004 | 171.660004 | 8434800 |
3 | 21/02/2019 | GS | 198.970001 | 199.45 | 195.05 | 196.360001 | 196.360001 | 2785900 |
4 | 21/02/2019 | FB | 161.929993 | 162.24 | 159.59 | 160.039993 | 160.039993 | 15607800 |
##先转换为NaN类型
data_Date = data_Date.replace(to_replace='?',value=np.nan)
data_Date
Date | Symbol | Open | High | Low | Close | Adj Close | Volume | |
---|---|---|---|---|---|---|---|---|
0 | 21/02/2019 | AAPL | 171.800003 | 172.369995 | 170.300003 | 171.059998 | 171.059998 | 17249700 |
1 | 21/02/2019 | JD | 24.820000 | NaN | NaN | 24.270000 | 24.270000 | 13542600 |
2 | 21/02/2019 | BABA | 171.000000 | 171.779999 | 169.800003 | 171.660004 | 171.660004 | 8434800 |
3 | 21/02/2019 | GS | 198.970001 | 199.449997 | 195.050003 | 196.360001 | 196.360001 | 2785900 |
4 | 21/02/2019 | FB | 161.929993 | 162.240005 | 159.589996 | 160.039993 | 160.039993 | 15607800 |
##判断是否有缺失值
##使用isnull()和any()组合方法
#data_Date.isnull().any()##使用any()可以快速查看是否有缺失值
pd.isnull(data_Date).any()
Date False
Symbol False
Open False
High True
Low True
Close False
Adj Close False
Volume False
dtype: bool
##使用notnull()和all()组合方法
data_Date.notnull().all()
Date True
Symbol True
Open True
High False
Low False
Close True
Adj Close True
Volume True
dtype: bool
any():有True,则返回True,全False才返回False;
all():有False,则返回False,全True才返回True
#用NaN该列的均值代替NaN
data_Date.fillna(data_Date.mean())
Date | Symbol | Open | High | Low | Close | Adj Close | Volume | |
---|---|---|---|---|---|---|---|---|
0 | 21/02/2019 | AAPL | 171.800003 | 172.369995 | 170.300003 | 171.059998 | 171.059998 | 17249700 |
1 | 21/02/2019 | JD | 24.820000 | 176.459999 | 173.685001 | 24.270000 | 24.270000 | 13542600 |
2 | 21/02/2019 | BABA | 171.000000 | 171.779999 | 169.800003 | 171.660004 | 171.660004 | 8434800 |
3 | 21/02/2019 | GS | 198.970001 | 199.449997 | 195.050003 | 196.360001 | 196.360001 | 2785900 |
4 | 21/02/2019 | FB | 161.929993 | 162.240005 | 159.589996 | 160.039993 | 160.039993 | 15607800 |
数据离散化
数据离散化(主要针对连续属性的数据离散化):在连续属性的值域上,将值域划分为若干个离散区间,最后用不同的符号或整数值代表落入到该区间的属性值的过程。简单点说就是将连续的数据分割多份,并给每份做上标记。
离散化的作用就是为了简化数据结构。一般的流程:
- 将数据进行分组:
- 自动分组:pd.qcut(data,q)–>q:组数;返回一个Series
- 自定义分组:pd.cut(data,[])–>[]:设定的区间;返回一个Series
- 对分组好的数据进行one-hot编码:
- pd.get_dummies(Series,prefix=None)–>prefix:前缀名
###有一组身高数据
height_info = pd.DataFrame({'age':[23,22,23,22],
'height':[170,180,176,162]},index=['Hajo','Mike','Joe','Shanel'])
height_info
age | height | |
---|---|---|
Hajo | 23 | 170 |
Mike | 22 | 180 |
Joe | 23 | 176 |
Shanel | 22 | 162 |
##现在按身高分为高,中,矮
##自动分组
sr1 = pd.qcut(height_info['height'],q=3)
sr1
Hajo (161.999, 170.0]
Mike (176.0, 180.0]
Joe (170.0, 176.0]
Shanel (161.999, 170.0]
Name: height, dtype: category
Categories (3, interval[float64]): [(161.999, 170.0] < (170.0, 176.0] < (176.0, 180.0]]
##自定义分组
sr2 = pd.cut(height_info['height'],[160,170,175,180])
sr2
Hajo (160, 170]
Mike (175, 180]
Joe (175, 180]
Shanel (160, 170]
Name: height, dtype: category
Categories (3, interval[int64]): [(160, 170] < (170, 175] < (175, 180]]
##分别对sr1和sr2进行one-hot 编码
d1 = pd.get_dummies(sr1)
d2 = pd.get_dummies(sr2)
print('sr1的one-hot编码:\n',d1)
print('sr2的one-hot编码:\n',d2)
sr1的one-hot编码:
(161.999, 170.0] (170.0, 176.0] (176.0, 180.0]
Hajo 1 0 0
Mike 0 0 1
Joe 0 1 0
Shanel 1 0 0
sr2的one-hot编码:
(160, 170] (170, 175] (175, 180]
Hajo 1 0 0
Mike 0 0 1
Joe 0 0 1
Shanel 1 0 0
以上全部就是本人学习Pandas库所整理的笔记,如有错误,欢迎指出!!!
数据资源链接:
链接:https://pan.baidu.com/s/1_OBCXvA8S4roQg4GK-JweA
提取码:7fb0