Pandas知识点总结
Pandas的数据结构
在pandas中有两类非常重要的数据结构,即序列Series和数据框DataFrame。Series类似于numpy中的一维数组,除了通吃一维数组可用的函数或方法,而且其可通过索引标签的方式获取数据,还具有索引的自动对齐功能;DataFrame类似于numpy中的二维数组,同样可以通用numpy数组的函数和方法,而且还具有其他灵活应用,后续会介绍到。
1.Series
- Series创建方式
是一维带标签的数组,数组里可以放任意的数据(整数,浮点数,字符串,Python Object)。其基本的创建函数是:
s=pd.Series(data,index=index)其中index是一个列表,用来作为数据的标签。data可以是不同的数据类型:
Python 字典
ndarry对象
一个标量值 ,如5
d = {'a':1,'b':2,'d':3} #从字典里创建
k = pd.Series(d,list("abcd"))
运行:
a 1.0
b 2.0
c NaN
d 3.0
s = pd.Series(np.random.randn(5),index=list("abcde")) #从numpy中创建Series
运行:
a 0.772053
b -1.624553
c 1.103055
d 0.275559
e 0.769579
dtype: float64
- Series对象的性质
* 类ndarry对象 ndarry里的方法也支持
* 类dict对象 类字典对象,字典中的方法也可以访问
* 标签对其操作 如果两个series相加,会自动寻找行标签值相同的行进行计算,若没有对应的行标签值,会累加形成一行
2.DataFrame
DataFrame 是一个二维带行标签和列标签的数组。可以吧DataFrame想象成一个Excel表格或一个SQL数据库的表格,
还可以想象成是一个Series对象字典。它是pandas里最常用的数据结构。
- 基本格式
df = pd.DataFrame(data,index = index,columns = columns)
其中index是行标签,columns是列标签,data可以是下面的数据:
- 由一维numpy数组,list,Series构成的字典
- 从Series字典创建 (从Series字典创建的DataFrame中Series长度可以不一样)
d={'one':pd.Series(np.random.randn(5),index=list("abcde")),
'tow':pd.Series(np.random.randn(5),index=list("abcde"))}
df = pd.DataFrame(d,index=['a','c','d']) #通过字典的Series创建 index是需要得到的行索引
- 从字典数组创建 (从字典数组中创建的DataFrame数组的长度必须一样)
d={'A':1,'B':pd.Timestamp('20130301'),'C':range(4),'D':np.arange(4)}
df = pd.DataFrame(d)
- 从列表创建
data = [(1,2,'java'),(3,4,'python')] #一个列表数据
pd.DataFrame(data,index=['one','tow'],columns=['a','b','c']) 指定行标签和列标签
4.列表字典
data=[{'a':1,'b':2},{'c':1,'d':2}]
5.复杂的元组创建(多维度)
data={('a','b'):{('A','B'):1,('A','C'):2},
('a','a'):{('A','C'):3,('A','B'):4},
('a','c'):{('A','B'):5,('A','C'):6},
('b','a'):{('A','C'):7,('A','B'):8},
('b','b'):{('A','D'):9,('A','B'):10},
}
pd.DataFrame(data)
- DataFrame特性
- 列选择/增加/删除
- 增加:dd[‘xx’]=xxx的形式新增列 / dd.insert(1,‘bar’,[…]) 在第一列后面插入一列名为bar
- 删除 : del dd[‘xx’] / dd.pop(‘xx’)使用pop方法也能删除一列
- 使用assign()方法来插入新列
dd.assign(Radio = dd['one']+dd['two']) #新增一列,列名为Radio ,assign方法括号里面可以直接传递函数 dd.assign(Radio = lambda x:x.one-x.two)
索引和选择
- 选择一列–>df[col] -->Series
- 根据行标签选择一行->df.loc[label]->Series
- 根据行位置选择一行->df.iloc[label] ->Series
- 选择多行->df[5:10]->DataFrame
- 根据布尔向量选择多行->df[bool_vector]->DataFrame
- 数据对齐
当我们做加法运算时,DataFrame会自动寻找行和列对应的标签进行计算,寻找不到的标签会显示NaN
使用numpy函数
pandas的数组可以直接使用numpy的科学计算函数,因为DataFrame内部结构是使用np的ndarray
使用numpy的asarray可以将pandas的数据转换成ndarry的数据 np.asarray(df2)
例如: np.sin(df)
panel数据及结构
- panel是三维带标签的数组,实际上,pandas的名称由来就是由panel演进的,即pan(el)-da[ta]-s.Panel比较少用,但依然是最重要的基础数据结构之一。
- items:坐标轴0,索引对应的元素是一个DataFrame
- major_axis:坐标轴1,DataFrame里的行标签
- minor_axis:坐标轴2,DataFrame里的列标签。
创建:
data = {‘Item1’:pd.DataFrame(np.random.randn(3,4)),‘Item2’:pd.DataFrame(np.random.randn(3,4))}
pn = pd.Panel(data)
第一个维度索引值pn.items 第二个维度索引值pn.major_axis 第三个维度索引值pn.minor_axis
pn.to_frame()将三维数据转换成二维数据
pandas的基础运
- 重新索引
k.reindex(index = list(‘fghijk’)) #重新制定索引,返回一个拷贝数据 index属性增加行,columns字段增加列 - 丢弃部分数据
df.drop([‘two’,‘four’],axis=1) 丢弃列,axis=0丢弃行 同样是拷贝一份数据出来 - 映射函数
df.apply(lambda x:x.max() - x.min() , axis=0) axis=0 按行传递x,axis=1按列传递x
df.applymap(lambda x: ‘%.03f’ % x) #每一个元素只显示小数点后面三位 - 排序和排名
s.rank(method=‘average’) - 数据唯一性及成员资格
s.value_counts(); 返回每个元素出现的个数
s.unique() 返回一个不重复的列表 某一列
s.isin([‘a’,‘b’]) 判断值是否在列表里面
索引
- 行索引
s.index 获取行索引
s.columns 列索引
df.index.name = ‘row’ //给索引一个名字 - 重复索引
s.index.is_unique 判断索引是否有重复索引
s.index.unique() 返回一个唯一索引列表 - 处理
s.groupby(s.index).sum() 行索引重复项求和 mean()求平均数 - 多级索引
可以将更高维度的数据展现成二维数据
pd.MutiIndex
tuples = list(zip(*[['bar','bar','baz','baz','foo','foo','qux','qux'],
['one','two','one','two','one','two','one','two']
]))
输出:
[('bar', 'one'),
('bar', 'two'),
('baz', 'one'),
('baz', 'two'),
('foo', 'one'),
('foo', 'two'),
('qux', 'one'),
('qux', 'two')]
index = pd.MultiIndex.from_tuples(tuples,names = ['first','seconds']) #创建两个行索引,第一个用元组中的第一个数,第二个用元组中的第二个数 !
df = pd.DataFrame(np.random.randn(8,2),index=index,columns=['A','B']) #columns代表列字段
pandas的分组运算
- 分组运算分为三步:拆分–应用—合并
拆分:根据什么进行分组?
应用:每个分组进行什么样的计算?
合并:把每个分组的计算结果合并起来。
2.其他的分组方式:
1.通过列表进行分组
2.通过自定义函数进行分组
3.通过索引级别进行分组
a.groupby(a.key1).mean() #根据key1进行分组求平均值
key=[1,1,2,3,1]
a.groupby(key).mean() #根据外部引用的key求平均值 可以传递一个数组人为干预数据进行分组
k = a['data1'].groupby([a['key1'],a['key2']]).sum() #对多个key进行分组求和,生成多维度的Series
a.groupby(a.dtypes,axis=1).sum() #按列的类型进行分组将分组数据求和,axis = 1 代表按列分组,
#通过字典进行分组
df = pd.DataFrame(np.random.randint(1,10,(5,5)),
columns=['a','b','c','d','e'],
index = ['Alice','Bob','Candy','Dark','Emily']
)
df.loc[1:2,1:3] = np.NaN;
mapping = {'a':'red','b':'red','c':'blue','d':'orange','e':'blue'}
df.groupby(mapping,axis=1).sum() #字典中值为red,是由a,b构成,所以分组时a+b列组成red列
def _group_key(idx):
print(idx)
return len(idx)
df.groupby(_group_key,axis=0).size() #根据函数进行分组
#多级索引分组
columns = pd.MultiIndex.from_arrays([['China','USA','China','USA','China'],
['A','A','B','C','B']
],names=['country','index']) #创建两个多级索引,取名为country和index
df = pd.DataFrame(np.random.randint(1,10,(5,5)),columns=columns)
df.groupby(level=['country'],axis=1).sum() #多级索引分组时可以根据索引名进行分组。axis=1指定列分组
聚合运算
- 内置的聚合函数
- sum() 求和
- mean() 求平均值
- max() 求最大值
- min() 求最小值
- describe() 对每个分组进行聚合(返回n个聚合结果)
- 自定义聚合函数
def peak_range(s) :
return s.max()-s.min();
dd.groupby('key1').agg(peak_range) #agg 使用自定义聚合函数,默认传递每一列的值
-
如果我们需要求多个聚合函数另外还需要加上自定义的聚合函数
dd.groupby(‘key1’).agg([‘std’,‘mean’,‘sum’],(‘range’,peak_range)) #peak_range为自定义聚合函数,range为别名如果我们想用对不同的列用不同的聚合函数(可以利用字典)
d={'data1':['mean',('range',peak_range)],'data2':'sum'}
dd.group('key1').agg(d) #data1求平均值以及一个自定义的聚合函数,data2求和
如果我想将分组后聚合的数据添加到原数据后面,不改变原数据形状
kk = df.groupby('key1').transform(np.mean).add_prefix('mean_')
kk #这样就得到跟元数据格式一样的一个聚合函数,我们只需要将其添加到原数据后面
3.transform调用自定义聚合函数
def demean(s):
return s-s.mean()
key['one','one','two','one','two']
demeand = df.groupby(key).transform(demean)
demeand
数据导入导出
- 一般数据步骤爬取,解析,清洗–>保存成csv格式
- 索引:将一个列或多个列读取出来构成DataFrame,其中涉及是否从文件中读取索引以及列名
- 类型推断和数据转换:包括用户自定义的转换以及缺失值标记
pd.read_csv('H:/datasets/tedata/ex1.csv') #简单读取csv文件 默认会将第一行的内容当作列名称
%more H:/datasets/tedata/ex1.csv #查看文件格式
pd.read_table('H:/datasets/tedata/ex1.csv',sep=',') #采用read_table需要制定分隔符
pd.read_csv('H:/datasets/tedata/ex2.csv',header=None,names=['a','b','c','d','e'],index_col=['e','b'])
#header=None指定读取的文件没有列名称 names 指定列名称 index_col指定行索引,可以指定多个
pd.read_table('H:/datasets/tedata/ex3.csv',sep='\s+') #使用正则表达式读取,分隔符空格不规则的数据,\s+代表一个或多个空格
pd.read_csv('H:/datasets/tedata/ex5.csv',na_values=['NA','NULL','foo']) #指定缺失值na_values指定读取文件时将与数组里数据相等的值看成NAN
#还可以指定某一列判断缺失值{'xx':['NA'],'kk':['11']}
tr = pd.read_csv('H:/datasets/tedata/ex6.csv',chunksize=1000) #每次读取1000行数据 返回一个迭代器,每调用一次读取1000行数据
result = pd.Series([])
for c in tr:
result = result.add(c['key'].value_counts(),fill_value=0)
print(result)
result.sort_values(ascending=False)
result[:10]
#每次读取到的数据都累加到result中,然后对result进行排序,求出出现次数最多的前10名
kk.to_csv('D:/datasets',index=False,header=None,columns=['a','b'],sep='|')
#index=False在写入文件时不写索引值 header=None指定写入时不写列标签 columns指定只写哪几列数据 sep指定写入时的分隔符
日期解析
- 迭代:针对大型文件进行逐块迭代。这个是pandas和python原生的csv库的最大区别
- 不规整数据问题:跳过一些行,或注释等等
import numpy as np
import pandas as pd
from datetime import datetime
from datetime import timedelta
now = datetime.now() #现在时间
delta.days #相差多少天
delta.total_seconds() #相差多少秒
date2+timedelta(4.5) #加上4天半
str(date1) #日期转字符串
date1.strftime('%Y/%m/%d %H:%M:%S') #格式化时间
datetime.strptime('2016-04-20 09:30:00','%Y-%m-%d %H:%M:%S') #将字符串转为日期
data = [datetime(2016,3,1),datetime(2016,3,2),datetime(2016,3,3),datetime(2016,3,4)]
s = pd.Series(np.random.randn(4),index=data)
s
#利用日期列表创建Series
pd.date_range('20160301','20160305') #使用开始日期和结束日期生成时间序列
pd.date_range('20160301',periods=10,normalize=True) #使用开始日期和个数生成时间序列 normalize=True去掉时间后面的毫秒值
pd.date_range(start='20160320',periods=10,freq='S') #freq指定生成的时间序列之间相隔的值
pd.Period(2010,freq='M') #创建一个特定的时期
pd.period_range('2018-01',periods=10,freq='M') #创建一个时期的序列
- 时间日期
- 时间戳Timestamp :固定的时刻->pd.Timestamp
- 固定日期periods :比如2016年3月份,再如2015年销售额->pd.Periods
- 时间间隔interval:由起始时间和结束时间来表示,固定时期是时间间隔的一个特殊
- 时间日期在pandas里的作用
- 分析金融数据,如股票交易数据
- 分析服务器日志
Timestamp和periods相互转化
d = pd.Series(np.random.randn(5),index = pd.date_range(start='20160320',periods=5,freq='M'))
k=d.to_period(freq='M') #将时间序列转化为时期的时间序列 以月为单位
相同的 xx.to_timestamp(how='end') #how='end' 代表以终止时间开始进行转换
- 时间的重采样
- 高频率–>低频率–>降频率 5分钟股票交易数据转化为日交易数据
- 低频率–>高频率–>升采样
- 其他重采样:每周三(w-wed)转换为每周五(w-FRI)
apply函数: apply()是一个DataFrame函数,参数是DataFrame也就是DataFrame中的Series
- df.apply(函数参数) 会将每一列作为一个函数参数传递进去
#apply函数在聚合函数中的应用
states = ['Ohio','New York','Vermont','Florida','Oregon','Nevada','California','Idaho']
group_key = ['East']*4+['West']*4
data = pd.Series(np.random.randn(8),index=states)
data[['Vermont','Nevada','Idaho']]=np.NaN
data
data.groupby(group_key).apply(lambda g:g.fillna(g.mean())) #用apply实现nan数据用平均值填充
- map() :是一个Series函数
参数是Seriers的每一个元素 - applymap()
将函数做用于DataFrame中的所有元素(elements)