import numpy as np
import pandas as pd
pandas中的数据结构有两种:Series和DataFrame。
Series
生成Series
obj=pd.Series([1,2,3,4],index=['a','b','c','d'])
obj
a 1
b 2
c 3
d 4
dtype: int64
Series可看成是定长、有序的字典结构,并且可以直接将Python字典转为Series:
sdata={
'Ohio':35000,
'Texas':71000,
'Oregon':16000,
'Utah':5000
}
obj_1=pd.Series(sdata)
obj_1
Ohio 35000
Oregon 16000
Texas 71000
Utah 5000
dtype: int64
Series可以存在缺失值:
states=['Calofornia','Ohio','Oregon','Texas']
obj_2=pd.Series(sdata,index=states)
obj_2
Calofornia NaN
Ohio 35000.0
Oregon 16000.0
Texas 71000.0
dtype: float64
属性
Series的常用属性为index与name。
obj_1.index
Index([‘Ohio’, ‘Oregon’, ‘Texas’, ‘Utah’], dtype=’object’)
Series的index可以直接更改:
obj_1.index=['state_1', 'state_2', 'state_3', 'state_4']
obj_1
state_1 35000
state_2 16000
state_3 71000
state_4 5000
dtype: int64
一个Series可以有自己的名字:
obj_2.name='population'
obj_2.index.name='state'
obj_2
state
Calofornia NaN
Ohio 35000.0
Oregon 16000.0
Texas 71000.0
Name: population, dtype: float64
索引
index索引
obj.loc['a']
1
obj.loc[['a','c','d']]
a 1
c 3
d 4
dtype: int64
布尔索引
obj[obj>2]
c 3
d 4
dtype: int64
基本运算
obj+2
a 3
b 4
c 5
d 6
dtype: int64
np.exp(obj)
a 2.718282
b 7.389056
c 20.085537
d 54.598150
dtype: float64
DataFrame
生成DataFrame
生成自定义生成DataFrame常用的方法是将Python字典转化为生成DataFrame:
states=['Ohio','Ohio','Ohio','Nevada','Nevada','Nevada']
years=[2000,2001,2002,2001,2002,2003]
pop=[1.5,1.7,3.6,2.4,2.9,3.2]
index=['one','two','three','four','five','six']
data={
'state':states,
'year':years,
'pop':pop
}
frame=pd.DataFrame(data,index=index,columns=['year','state','pop'])
frame
属性
DataFrame的常用属性有index与values。
frame.index
Index([‘one’, ‘two’, ‘three’, ‘four’, ‘five’, ‘six’], dtype=’object’)
frame.values
数据预览
frame.sample(3) #按行随机采样
增删查改
因为DataFrame属于表格型数据结构,所以增删查改的操作非常重要。
查
查询数据的方式主要有两种方法:loc与iloc,分别是根据标签索引与根据数字序号索引。
frame.loc[:,['state']] #单列
frame.loc[['two'],:] #单行
frame.loc[['three'],['pop']] #单个数值
frame.loc['four':'six',['state','pop']] #多行多列,非连续.注意字符形式的切片是闭区间
frame.iloc[3:6,[1,2]] #多行多列,非连续,注意数字形式的切片是开区间
frame[frame['pop']>3] #布尔索引
增
frame['eastern']=(frame.loc[:,'state']=='Ohio') #增加列
frame
frame_2=frame.reindex(['one','two','three','inter','four','five','six']) #增加行
frame_2
删
frame_1=frame.drop(['year','eastern'],axis=1,inplace=False) #删除列
frame_1
frame_2=frame.drop(['three','five'],axis=0,inplace=False) #删除行
frame_2
改
frame.loc[['two'],['pop']]=2.5 #改数据
frame
DF与DF的运算
df1=pd.DataFrame(np.arange(9).reshape((3,3)),index=['Ohio','Texas','Colorado'],columns=list('bcd'))
df2=pd.DataFrame(np.arange(12).reshape((4,3)),index=['Utah','Ohio','Texas','Oregon'],columns=list('bde'))
print("df1:\n{}".format(df1))
print("df2:\n{}".format(df2))
df1+df2 #df之间的加法,得到的数据为两表的交集,而标签为两表的并集
DF与Series的运算
在numpy中,一个矩阵与一个向量做运算会有广播机制,类似的,DF与Series做运算时也有广播机制。
frame=pd.DataFrame(np.arange(6).reshape((2,3)),index=np.arange(2),columns=list('abc'))
series=frame.iloc[0]
frame
series
a 0
b 1
c 2
Name: 0, dtype: int32
frame-series
应用函数
可以使用apply()与applymap()方法将一个函数应用到df的行列或每一个数据上。
frame=pd.DataFrame(np.random.randn(3,3),index=['Utah','Ohio','Texas'],columns=list('abc'))
frame
f_1=lambda x:x.max()-x.min() #计算取值范围
f_2=lambda x:'%.2f' %x #取两位有效数字
frame.applymap(f_2) #对每一个数据都应用f_2函数
frame.apply(f_1,axis=0) #计算每一列的范围
a 2.172817
b 1.145203
c 1.677505
dtype: float64
frame.apply(f_1,axis=1) #计算每一行的范围
Utah 1.811939
Ohio 1.136488
Texas 1.611686
dtype: float64
排序与排名
frame=pd.DataFrame(np.arange(9).reshape((3,3)),index=['two','one','three'],columns=list('bca'))
frame
按标签排序
frame.sort_index(axis=0) #按行标签排序
frame.sort_index(axis=1) #按列标签排序
按数值排序
frame.sort_values(by='c',ascending=False) #指定对'c'列降序排列
排名
(待补充)
统计方法
values=np.array([
[1.4,np.nan],
[7.1,-4.5],
[np.nan,np.nan],
[0.75,-1.3]
])
frame=pd.DataFrame(values,index=(['a','b','c','d']),columns=['one','two'])
frame
frame.mean(axis=0)
one 3.083333
two -2.900000
dtype: float64
frame.sum(axis=1)
a 1.40
b 2.60
c NaN
d -0.55
dtype: float64
frame.describe()
frame.info()
相关系数与协方差
price = pd.read_pickle('examples/yahoo_price.pkl')
volume = pd.read_pickle('examples/yahoo_volume.pkl')
returns = price.pct_change()
returns.sample(3)
returns.corr() #相关系数矩阵
returns.cov() #协方差矩阵
独特值,值的计数
frame=pd.DataFrame({
'C1':[1,3,4,3,4],
'C2':[2,3,1,2,3],
'C3':[1,5,2,4,4]
})
frame.loc[:,'C1'].unique()
array([1, 3, 4], dtype=int64)
frame.loc[:,'C3'].value_counts(sort=False)
1 1
2 1
4 2
5 1
Name: C3, dtype: int64
布尔筛选
mask=frame.loc[:,'C2'].isin([1,2])
mask
0 True
1 False
2 True
3 True
4 False
Name: C2, dtype: bool
DF数据计数
result=frame.apply(pd.value_counts).fillna(0)
result
pandas进阶
类别型数据
obj=pd.Series(['apple','orange','banana','apple']*2)
pd.value_counts(obj)
许多数据仓库都有特殊的方式来存放重复值已增加存储和计算的效率,在数据仓库中一个最佳的实用方法是使用fact table来存储可运算的数据,再使用dimension table来存储描述性信息。如上述Series用两个表来存储的话如下所示:
fact=pd.Series([0,1,2,0]*2)
dim=pd.Series(['apple','orange','banana'])
dim.take(fact)
上述例子中的独特值’apple’与’orange’被称为类别或字典,而整数值被称为类别码,这种表达(存储)方式被称为类别编码或字典编码形式。这种方式会大大降低以下两种场景的开销:
- 类别重命名
- 在不改变已有类别顺序的情况下增加一个类别
fruits=['apple','orange','banana','apple']*2
df=pd.DataFrame({
'fruit':fruits,
'basket_id':np.arange(len(fruits)),
'count':np.random.randint(3,15,size=len(fruits)),
'weight':np.random.uniform(0,4,size=len(fruits))},
columns=['basket_id','fruit','count','weight']
)
df.loc[:,'fruit']=df.loc[:,'fruit'].astype('category')
df.loc[:,'fruit']
类别型数据列取cat属性后得到一个类别型实例,它有两个属性,categories和codes:
c=df.loc[:,'fruit'].cat
print('{}\n{}'.format(c.categories,c.codes))
直接由字符串列表生成类别型:
str_list=['foo','bar','baz','foo','bar']
categories=pd.Categorical(str_list)
categories
由类别与编码生成类别型:
category_list=['foo','bar','baz']
codes_list=[0,1,2,0,0,1]
categories=pd.Categorical.from_codes(codes_list,category_list,ordered=True)
categories
类别计算
之前用过的cut()与qcut()方法返回的就是类别型,有些pandas操作在使用类别型时会有更好的表现,如groupby():
samples=np.random.randn(100)
bins=pd.qcut(samples,4,labels=['Q1','Q2','Q3','Q4'])
bins
bins.codes[:5]
bins=pd.Series(bins,name='quartile')
stat_result=pd.Series(samples).groupby(bins).agg(['min','max','mean']).reset_index()
stat_result
对于那些重复值很多的数据集而言,将其转化到类别型是很有用的,包括性能提升与更小的存储开销,看下面例子:
N=10000000
strs=pd.Series(['a','b','c','d']*(N//4)) #字符串型
cats=strs.astype('category') #类别型
print(strs.memory_usage(),cats.memory_usage()) #内存使用差异
类别型方法
对于Series:
s=pd.Series(['a','b','c','d'])
cats1=s.astype('category')
cats2=cats1.cat.set_categories(['a','b','c','d','e']) #改变类别
cats1.value_counts()
cats2.value_counts()
cats2.cat.remove_unused_categories()
当使用统计分析或者机器学习工具时,常需要将类别型转换成哑变量,或者是独热码:
cats=pd.Series(['a','b','c','a'],dtype='category')
pd.get_dummies(cats)
GroupBy进阶
组转换与展开GroupBy
df=pd.DataFrame({
'key':['a','b','c']*2,
'val':np.arange(6)
})
df.groupby('key').mean()
假设需要对’a’,’b’,’c’组的值用各组的均值来替换,可以使用transform()方法,这被称为展开GroupBy:
df.groupby('key').transform('mean')
transform()方法提供了类似于apply()方法的功能,不过有更多的限制:
- 它的输出与输入同形状
- 不改变输入
再看一个例子,将组里的每一个元素标准化:
def normalize(x):
return (x-x.mean())/x.std()
df.groupby('key').transform(normalize)
分组时间重采样
(待补充)
方法链接技术
(待补充)