微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Python科学计算之Pandas详解

起步

Pandas最初被作为金融数据分析工具而开发出来,因此 pandas 为时间序列分析提供了很好的支持。 Pandas 的名称来自于面板数据(panel data)和python数据分析 (data analysis) 。panel data是经济学中关于多维数据集的一个术语,在Pandas中也提供了panel的数据类型。

在我看来,对于 Numpy 以及 Matplotlib ,Pandas可以帮助创建一个非常牢固的用于数据挖掘与分析的基础。而Scipy当然是另一个主要的也十分出色的科学计算库。

安装与导入

通过pip进行安装: pip install pandas

导入:

import pandas as pd

Pandas的数据类型

Pandas基于两种数据类型: series 与 dataframe 。

Series

一个series是一个一维的数据类型,其中每一个元素都有一个标签。类似于Numpy中元素带标签的数组。其中,标签可以是数字或者字符串。

# coding: utf-8
import numpy as np
import pandas as pd

s = pd.Series([1,2,5,np.nan,6,8])
print s

输出

0 1.0
1 2.0
2 5.0
3 NaN
4 6.0
5 8.0
dtype: float64

DataFrame

一个dataframe是一个二维的表结构。Pandas的dataframe可以存储许多种不同的数据类型,并且每一个坐标轴都有自己的标签。你可以把它想象成一个series的字典项。

创建一个 DateFrame:

#创建日期索引序列 
dates = pd.date_range('20130101',periods=6)
#创建Dataframe,其中 index 决定索引序列,columns 决定列名
df = pd.DataFrame(np.random.randn(6,4),index=dates,columns=list('ABCD'))
print df

输出

   A  B  C  D
2013-01-01 -0.334482 0.746019 -2.205026 -0.803878
2013-01-02 2.007879 1.559073 -0.527997 0.950946
2013-01-03 -1.053796 0.438214 -0.027664 0.018537
2013-01-04 -0.208744 -0.725155 -0.395226 -0.268529
2013-01-05 0.080822 -1.215433 -0.785030 0.977654
2013-01-06 -0.126459 0.426328 -0.474553 -1.968056

字典创建 DataFrame

df2 = pd.DataFrame({ 'A' : 1.,'B' : pd.Timestamp('20130102'),'C' : pd.Series(1,index=list(range(4)),dtype='float32'),'D' : np.array([3] * 4,dtype='int32'),'E' : pd.Categorical(["test","train","test","train"]),'F' : 'foo' })

输出

 A  B C D E F
0 1 2013-01-02 1 3 test foo
1 1 2013-01-02 1 3 train foo
2 1 2013-01-02 1 3 test foo
3 1 2013-01-02 1 3 train foo

文件数据导入Pandas

df = pd.read_csv("Average_Daily_Traffic_Counts.csv",header = 0)
df.head()

数据源可以是 英国政府数据 或 美国政府数据 来获取数据源。当然, kaggle 是另一个好用的数据源。

选择/切片

# 选择单独的一列,返回 Serires,与 df.A 效果相当。
df['A']

# 位置切片
df[0:3]

# 索引切片
df['20130102':'20130104']

# 通过标签选择
df.loc[dates[0]]

# 对多个轴同时通过标签进行选择
df.loc[:,['A','B']]

# 获得某一个单元的数据
df.loc[dates[0],'A']
# 或者
df.at[dates[0],'A'] # 速度更快的做法

# 通过位置进行选择
df.iloc[3]

# 切片
df.iloc[3:5,0:2]

# 列表选择
df.iloc[[1,4],[0,2]]

# 获得某一个单元的数据
df.iloc[1,1]
# 或者
df.iat[1,1] # 更快的做法

# 布尔索引
df[df.A > 0]

# 获得大于零的项的数值
df[df > 0]

# isin 过滤
df2[df2['E'].isin(['two','four'])]

赋值

# 新增一列,根据索引排列
s1 = pd.Series([1,3,4,6],index=pd.date_range('20130102',periods=6))
df['F'] = s1

# 缺省项
# 在 pandas 中使用 np.nan 作为缺省项的值。
df1 = df.reindex(index=dates[0:4],columns=list(df.columns) + ['E'])
df1.loc[dates[0]:dates[1],'E'] = 1

# 删除所有带有缺省项的行
df1.dropna(how='any')

# 填充缺省项
df1.fillna(value=5)

# 获得缺省项的布尔掩码
pd.isnull(df1)

观察操作

# 观察开头的数据
df.head()

# 观察末尾的数据
df.tail(3)

# 显示索引
df.index

# 显示列
df.columns

# 显示底层 numpy 结构
df.values

# DataFrame 的基本统计属性预览
df.describe()
"""
  A  B  C  D
count 6.000000 6.000000 6.000000 6.000000 #数量
mean 0.073711 -0.431125 -0.687758 -0.233103 #平均值
std 0.843157 0.922818 0.779887 0.973118 #标准差
min -0.861849 -2.104569 -1.509059 -1.135632 #最小值
25% -0.611510 -0.600794 -1.368714 -1.076610 #正态分布 25%
50% 0.022070 -0.228039 -0.767252 -0.386188 #正态分布 50%
75% 0.658444 0.041933 -0.034326 0.461706 #正态分布 75%
max 1.212112 0.567020 0.276232 1.071804 #最大值
"""

# 转置
df.T

# 根据某一轴的索引进行排序
df.sort_index(axis=1,ascending=False)

# 根据某一列的数值进行排序
df.sort(columns='B')

统计

# 求平均值
df.mean()
"""
A -0.004474
B -0.383981
C -0.687758
D 5.000000
F 3.000000
dtype: float64
"""

# 指定轴上的平均值
df.mean(1)

# 不同维度的 pandas 对象也可以做运算,它会自动进行对应,shift 用来做对齐操作。
s = pd.Series([1,8],index=dates).shift(2)
"""
2013-01-01 NaN
2013-01-02 NaN
2013-01-03 1
2013-01-04 3
2013-01-05 5
2013-01-06 NaN
Freq: D,dtype: float64
"""

# 对不同维度的 pandas 对象进行减法操作
df.sub(s,axis='index')
"""
   A  B  C D F
2013-01-01 NaN NaN NaN NaN NaN
2013-01-02 NaN NaN NaN NaN NaN
2013-01-03 -1.861849 -3.104569 -1.494929 4 1
2013-01-04 -2.278445 -3.706771 -4.039575 2 0
2013-01-05 -5.424972 -4.432980 -4.723768 0 -1
2013-01-06 NaN NaN NaN NaN NaN
"""

函数应用

# 累加
df.apply(np.cumsum)

直方图

s = pd.Series(np.random.randint(0,7,size=10))
s.value_counts()
"""
4 5
6 2
2 2
1 1
dtype: int64
String Methods
"""

字符处理

s = pd.Series(['A','B','C','Aaba','Baca','CABA','dog','cat'])
s.str.lower()
"""
0 a
1 b
2 c
3 aaba
4 baca
5 NaN
6 caba
7 dog
8 cat
dtype: object
"""

合并

使用 concat() 连接 pandas 对象:

df = pd.DataFrame(np.random.randn(10,4))
"""
  0  1  2  3
0 -0.548702 1.467327 -1.015962 -0.483075
1 1.637550 -1.217659 -0.291519 -1.745505
2 -0.263952 0.991460 -0.919069 0.266046
3 -0.709661 1.669052 1.037882 -1.705775
4 -0.919854 -0.042379 1.247642 -0.009920
5 0.290213 0.495767 0.362949 1.548106
6 -1.131345 -0.089329 0.337863 -0.945867
7 -0.932132 1.956030 0.017587 -0.016692
8 -0.575247 0.254161 -1.143704 0.215897
9 1.193555 -0.077118 -0.408530 -0.862495
"""

pieces = [df[:3],df[3:7],df[7:]]
pd.concat(pieces)
"""
  0  1  2  3
0 -0.548702 1.467327 -1.015962 -0.483075
1 1.637550 -1.217659 -0.291519 -1.745505
2 -0.263952 0.991460 -0.919069 0.266046
3 -0.709661 1.669052 1.037882 -1.705775
4 -0.919854 -0.042379 1.247642 -0.009920
5 0.290213 0.495767 0.362949 1.548106
6 -1.131345 -0.089329 0.337863 -0.945867
7 -0.932132 1.956030 0.017587 -0.016692
8 -0.575247 0.254161 -1.143704 0.215897
9 1.193555 -0.077118 -0.408530 -0.862495
"""

join 合并:

left = pd.DataFrame({'key': ['foo','foo'],'lval': [1,2]})
right = pd.DataFrame({'key': ['foo','rval': [4,5]})
pd.merge(left,right,on='key')
"""
 key lval rval
0 foo 1 4
1 foo 1 5
2 foo 2 4
3 foo 2 5
"""

追加

在 dataframe 数据后追加行

df = pd.DataFrame(np.random.randn(8,columns=['A','D'])
s = df.iloc[3]
df.append(s,ignore_index=True)

分组

分组常常意味着可能包含以下的几种的操作中一个或多个

  • 依据一些标准分离数据
  • 对组单独地应用函数
  • 将结果合并到一个数据结构中
df = pd.DataFrame({'A' : ['foo','bar','foo','B' : ['one','one','two','three','three'],'C' : np.random.randn(8),'D' : np.random.randn(8)})

# 对单个分组应用函数,数据被分成了 bar 组与 foo 组,分别计算总和。
df.groupby('A').sum()

# 依据多个列分组会构成一个分级索引
df.groupby(['A','B']).sum()
"""
   C  D
A B   
bar one -1.814470 2.395985
 three -0.595447 0.166599
 two -0.392670 -0.136473
foo one -1.195665 -0.616981
 three 1.928123 -1.623033
 two 2.414034 1.600434
"""

数据透视表

df = pd.DataFrame({'A' : ['one','three'] * 3,'B' : ['A','C'] * 4,'C' : ['foo','bar'] * 2,'D' : np.random.randn(12),'E' : np.random.randn(12)})

# 生成数据透视表
pd.pivot_table(df,values='D',index=['A','B'],columns=['C'])
"""
C  bar foo
A B   
one A -0.773723 1.418757
 B -0.029716 -1.879024
 C -1.146178 0.314665
three A 1.006160 NaN
 B NaN -1.035018
 C 0.648740 NaN
two A NaN 0.100900
 B -1.170653 NaN
 C NaN 0.536826
"""

时间序列

pandas 拥有既简单又强大的频率变换重新采样功能,下面的例子从 1次/秒 转换到了 1次/5分钟:

rng = pd.date_range('1/1/2012',periods=100,freq='S')
ts = pd.Series(np.random.randint(0,500,len(rng)),index=rng)
ts.resample('5Min',how='sum')
"""
2012-01-01 25083
Freq: 5T,dtype: int32
"""

# 本地化时区表示
rng = pd.date_range('3/6/2012 00:00',periods=5,freq='D')
ts = pd.Series(np.random.randn(len(rng)),rng)
"""
2012-03-06 0.464000
2012-03-07 0.227371
2012-03-08 -0.496922
2012-03-09 0.306389
2012-03-10 -2.290613
Freq: D,dtype: float64
"""

ts_utc = ts.tz_localize('UTC')
"""
2012-03-06 00:00:00+00:00 0.464000
2012-03-07 00:00:00+00:00 0.227371
2012-03-08 00:00:00+00:00 -0.496922
2012-03-09 00:00:00+00:00 0.306389
2012-03-10 00:00:00+00:00 -2.290613
Freq: D,dtype: float64
"""

# 转换为周期
ps = ts.to_period()

# 转换为时间戳
ps.to_timestamp()

分类

df = pd.DataFrame({"id":[1,"raw_grade":['a','b','a','e']})

# 将 raw_grades 转换成 Categoricals 类型
df["grade"] = df["raw_grade"].astype("category")
df["grade"]
"""
0 a
1 b
2 b
3 a
4 a
5 e
Name: grade,dtype: category
Categories (3,object): [a,b,e]
"""

# 重命名分类
df["grade"] = df["grade"].cat.set_categories(["very bad","bad","medium","good","very good"])

# 根据分类的顺序对数据进行排序
df.sort("grade")
"""
 id raw_grade  grade
5 6   e very bad
1 2   b  good
2 3   b  good
0 1   a very good
3 4   a very good
4 5   a very good
"""

作图

ts = pd.Series(np.random.randn(1000),index=pd.date_range('1/1/2000',periods=1000))
ts = ts.cumsum()
ts.plot()

数据IO

# 从 csv 文件读取数据
pd.read_csv('foo.csv')

# 保存到 csv 文件
df.to_csv('foo.csv')

# 读取 excel 文件
pd.read_excel('foo.xlsx','Sheet1',index_col=None,na_values=['NA'])

# 保存到 excel 文件
df.to_excel('foo.xlsx',sheet_name='Sheet1')

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家学习或者使用python能带来一定的帮助,如果有疑问大家可以留言交流。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐