本篇文章主要是针对pandas的基础运用,做简单的记录汇总,加深印象,以官方网站的api做练习。
官方网址:http://pandas.pydata.org/pandas-docs/stable/10min.html
主要包括DataFrame、Series数据类型的切片取值、索引取值、缺失值处理、筛选、更改值、填充、关联、合并、append、分组、以及stack、unstack,和透视表用法,以及运算、画图、时间序列。。这些用法算是pandas入门最基本的掌握,后面会继续学习高级的pandas用法,因为pandas处理数据真的太强大了,下次会举些项目例子。
# 导入需要的包
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# np.nan是数值型,pd.NaT是object类型
s = pd.Series([1,3,5,np.nan,6,8])
下面图片可以看到具体生成s的数据类型
# 利用datetime数据格式做索引,创建DataFrame。
dates = pd.date_range('20130101', periods=6)
df = pd.DataFrame(np.random.randn(6,4), index=dates, columns=list('ABCD'))
# 利用dict数据对象创建DataFrame,注意pd.Timestamp和pd.Categorical这两个对象
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' })
# 结果如下:
df2
Out[11]:
A B C D E F
0 1.0 2013-01-02 1.0 3 test foo
1 1.0 2013-01-02 1.0 3 train foo
2 1.0 2013-01-02 1.0 3 test foo
3 1.0 2013-01-02 1.0 3 train foo
# 每一列的数据类型查看
df2.dtypes
Out[12]:
A float64
B datetime64[ns]
C float32
D int32
E category
F object(字符串是object型)
dtype: object
查看数据
# 默认是前5行数据
df.head()
# 指定最后3行数据
df.tail(3)
# 查看索引
df.index
# 查看所有列名
df.columns
# 查看值
df.values
# 展示DataFrame的数据统计情况,包括计数、平均值、最小值、最大、标准差等数据指标
df.describe()
# 数据转置查看,也就是原来的列成为索引,原来的索引成为列
df.T
# 根据某一轴,索引排序,下面选axis=1是根据列名排序,ascending=False表示降序,ascending=True表示升序
df.sort_index(axis=1, ascending=False)
# 根据某一列,值排序,下面以列名B值进行排序,默认是升序,从小到大
df.sort_values(by='B')
筛选数据
# 选择某一列
df['A']
# 选择某些行,比如下面选择索引是0,1,2,也就是前三行,因为虽然索引是其他标记别名,其实内部还是以0,1,2,3……的索引,所以就可以根据0,1,2等或者切片去选择行
df[0:3]
# 同理,用已有的索引名获取第2行、第3行,第4行,发现了没有,如果用默认的0,1,2,3……,切片时不含尾标的,但用已有的索引名,切片时含有尾标。你可以打印查看
df['20130102':'20130104']
####
# 选择某一行,如果你用df[0]就会报错了,这个可不是选择第一行啊。df.loc[0]也会报错,df.iloc[0]才是正确的。后面介绍df.loc和df.iloc的区别
df.loc[dates[0]] # 正确,因为dates[0]是已定义的索引别名,而如果用df.loc[0]就错误,当然df.iloc[0]这个是可以用默认的0,1,2等索引,是正确的。
df.iloc[0] # 正确,但df.iloc[dates[0]]就错误了,这个说明了df.iloc和df.loc的区别
# 行和列同时选
df.loc[:,['A','B']]
df.loc['20130102':'20130104',['A','B']]
df.loc[dates[0],'A'] 和 df.at[dates[0],'A'] 等同,只不过df.at更快的获取该值,并且df.at不支持获取多个值。
# 和前面介绍的一样,df.loc和df.iloc的区别,df.iloc只能用默认的索引和列名,也就是0,1,2,3,4……
df.iloc[3:5,0:2]
df.iloc[[1,2,4],[0,2]]
df.iloc[1:3,:]
df.iloc[:,1:3]
df.iloc[1,1] 和 df.iat[1,1] 等同
#############################
# 根据布尔类型筛选数据
# 根据某列大于某值做判断筛选,其实就是一列布尔类型值代入到DataFrame中筛选
df[df.A > 0]
Out[39]:
A B C D
2013-01-01 0.469112 -0.282863 -1.509059 -1.135632
2013-01-02 1.212112 -0.173215 0.119209 -1.044236
2013-01-04 0.721555 -0.706771 -1.039575 0.271860
# 根据DataFrame的值做判断筛选,这是满足条件就筛选出来,不满足就会变为NaN
df[df > 0]
Out[40]:
A B C D
2013-01-01 0.469112 NaN NaN NaN
2013-01-02 1.212112 NaN 0.119209 NaN
2013-01-03 NaN NaN NaN 1.071804
2013-01-04 0.721555 NaN NaN 0.271860
2013-01-05 NaN 0.567020 0.276232 NaN
2013-01-06 NaN 0.113648 NaN 0.524988
# 复制df
df2 = df.copy()
# 对df2新增一列
df2['E'] = ['one', 'one','two','three','four','three']
# 根据isin判断做筛选,其实还是某一列的
df2[df2['E'].isin(['two','four'])]
更改值
s1 = pd.Series([1,2,3,4,5,6], index=pd.date_range('20130102', periods=6))
# 下面就把列名F值去改变,赋值是Series数据
df['F'] = s1
# 同样,把列名'D'去改变,赋值np.array数据
df.loc[:,'D'] = np.array([5] * len(df))
# 根据索引➕列名去更改某一个值
df.at[dates[0],'A'] = 0
# 根据默认索引➕列名去更改某一值
df.iat[0,1] = 0
# 根据条件去更改值
df2 = df.copy()
df2[df2 > 0] = -df2
缺失数据
# 缺失数据一般用np.nan表示,默认情况不会参与计算
# 改变df的索引,列名,生成新的DataFrame数据
df1 = df.reindex(index=dates[0:4], columns=list(df.columns) + ['E'])
# 对0,1行,E列对应的数据更改数据值
df1.loc[dates[0]:dates[1],'E'] = 1
df1
Out[57]:
A B C D F E
2013-01-01 0.000000 0.000000 -1.509059 5 NaN 1.0
2013-01-02 1.212112 -0.173215 0.119209 5 1.0 1.0
2013-01-03 -0.861849 -2.104569 -0.494929 5 2.0 NaN
2013-01-04 0.721555 -0.706771 -1.039575 5 3.0 NaN
# dropna函数功能:丢弃缺失值,参数how=‘any’只要任一行存在缺失值,就丢弃。
df1.dropna(how='any')
Out[58]:
A B C D F E
2013-01-02 1.212112 -0.173215 0.119209 5 1.0 1.0
# fillna函数对缺失值填充
df1.fillna(value=5)
Out[59]:
A B C D F E
2013-01-01 0.000000 0.000000 -1.509059 5 5.0 1.0
2013-01-02 1.212112 -0.173215 0.119209 5 1.0 1.0
2013-01-03 -0.861849 -2.104569 -0.494929 5 2.0 5.0
2013-01-04 0.721555 -0.706771 -1.039575 5 3.0 5.0
# isna判断缺失值
pd.isna(df1)
Out[60]:
A B C D F E
2013-01-01 False False False False True False
2013-01-02 False False False False False False
2013-01-03 False False False False False True
2013-01-04 False False False False False True
运算
# 列的平均值,如果是行的平均值,参数axis=1即可,默认是0
df.mean()
Out[61]:
A -0.004474
B -0.383981
C -0.687758
D 5.000000
F 3.000000
dtype: float64
# axis=1的情况
df.mean(1)
Out[62]:
2013-01-01 0.872735
2013-01-02 1.431621
2013-01-03 0.707731
2013-01-04 1.395042
2013-01-05 1.883656
2013-01-06 1.592306
Freq: D, dtype: float64
# 值推移
s = pd.Series([1,3,5,np.nan,6,8], index=dates).shift(2)
# 可以看到原2013-01-01、2013-01-02索引 对应的值向下推移了2行,同时nan值补充上。
s
Out[64]:
2013-01-01 NaN
2013-01-02 NaN
2013-01-03 1.0
2013-01-04 3.0
2013-01-05 5.0
2013-01-06 NaN
Freq: D, dtype: float64
# DataFrame数据与Series数据做运算,用到广播概念,sub是相减
df.sub(s, axis='index')
apply函数
默认在列上
df.apply(np.cumsum)
df.apply(lambda x: x.max() - x.min())
统计值出现的次数
s = pd.Series(np.random.randint(0, 7, size=10))
s
Out[69]:
0 4
1 2
2 1
3 2
4 6
5 4
6 4
7 6
8 4
9 4
dtype: int64
# 统计每个值出现的次数
s.value_counts()
Out[70]:
4 5
6 2
2 2
1 1
dtype: int64
字符串方法
s = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca', np.nan, 'CABA', 'dog', 'cat'])
s.str.lower()
合并
# 相当于sql语句中的union all
df = pd.DataFrame(np.random.randn(10, 4))
df
Out[74]:
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
# 先拆开,再用concat合起来
pieces = [df[:3], df[3:7], df[7:]]
pd.concat(pieces)
Out[76]:
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
关联
left = pd.DataFrame({'key': ['foo', 'foo'], 'lval': [1, 2]})
right = pd.DataFrame({'key': ['foo', 'foo'], 'rval': [4, 5]})
left
Out[79]:
key lval
0 foo 1
1 foo 2
#
right
Out[80]:
key rval
0 foo 4
1 foo 5
# 下面以列名key去关联
pd.merge(left, right, on='key')
Out[81]:
key lval rval
0 foo 1 4
1 foo 1 5
2 foo 2 4
3 foo 2 5
#
left = pd.DataFrame({'key': ['foo', 'bar'], 'lval': [1, 2]})
right = pd.DataFrame({'key': ['foo', 'bar'], 'rval': [4, 5]})
#
left
Out[84]:
key lval
0 foo 1
1 bar 2
#
right
Out[85]:
key rval
0 foo 4
1 bar 5
# 主要和上面的那个例子作对比,这个例子主要说明默认连接是:内连接
In [86]: pd.merge(left, right, on='key')
Out[86]:
key lval rval
0 foo 1 4
1 bar 2 5
append
df = pd.DataFrame(np.random.randn(8, 4), columns=['A','B','C','D'])
df
Out[88]:
A B C D
0 1.346061 1.511763 1.627081 -0.990582
1 -0.441652 1.211526 0.268520 0.024580
2 -1.577585 0.396823 -0.105381 -0.532532
3 1.453749 1.208843 -0.080952 -0.264610
4 -0.727965 -0.589346 0.339969 -0.693205
5 -0.339355 0.593616 0.884345 1.591431
6 0.141809 0.220390 0.435589 0.192451
7 -0.096701 0.803351 1.715071 -0.708758
# 获取第三行
s = df.iloc[3]
# 把s添加在df中,牛逼的pandas!
df.append(s, ignore_index=True)
Out[90]:
A B C D
0 1.346061 1.511763 1.627081 -0.990582
1 -0.441652 1.211526 0.268520 0.024580
2 -1.577585 0.396823 -0.105381 -0.532532
3 1.453749 1.208843 -0.080952 -0.264610
4 -0.727965 -0.589346 0.339969 -0.693205
5 -0.339355 0.593616 0.884345 1.591431
6 0.141809 0.220390 0.435589 0.192451
7 -0.096701 0.803351 1.715071 -0.708758
8 1.453749 1.208843 -0.080952 -0.264610
分组
df = pd.DataFrame({'A' : ['foo', 'bar', 'foo', 'bar',
'foo', 'bar', 'foo', 'foo'],
'B' : ['one', 'one', 'two', 'three',
'two', 'two', 'one', 'three'],
'C' : np.random.randn(8),
'D' : np.random.randn(8)})
# 以列A去分组,然后分组后求和,看出默认忽略了B列,因为B列是字符串类型,sum函数不支持
df.groupby('A').sum()
Out[93]:
C D
A
bar -2.802588 2.42611
foo 3.146492 -0.63958
# 同样可以
df.groupby(['A','B']).sum()
下面的图纠正一处错误,利用stack函数,是把列名作为DataFrame的索引,也就多加了一内层索引,不是截图说的作为某一列的值。
透视表
时间序列,这里不做详解
类别数据类型
df = pd.DataFrame({"id":[1,2,3,4,5,6], "raw_grade":['a', 'b', 'b', 'a', 'a', 'e']})
# 数据类型转变为category数据类型,并赋值给grade列,相当于有3列名
# id,raw_grade,grade
df["grade"] = df["raw_grade"].astype("category")
df["grade"]
Out[129]:
0 a
1 b
2 b
3 a
4 a
5 e
Name: grade, dtype: category
Categories (3, object): [a, b, e]
# 更改之前的category数据,用Series.cat.categories函数,之前是Categories (3, object): [a, b, e],更改后变为["very good", "good", "very bad"],一一对应
df["grade"].cat.categories = ["very good", "good", "very bad"]
# 利用set_categories设置类别有哪些,比如原来是 ["very good", "good", "very bad"],也就3个类别,现在变为["very bad", "bad", "medium", "good", "very good"],共5个类别。
df["grade"] = df["grade"].cat.set_categories(["very bad", "bad", "medium", "good", "very good"])
#
df["grade"]
Out[132]:
0 very good
1 good
2 good
3 very good
4 very good
5 very bad
Name: grade, dtype: category
Categories (5, object): [very bad, bad, medium, good, very good]
df["grade"]
Out[132]:
0 very good
1 good
2 good
3 very good
4 very good
5 very bad
Name: grade, dtype: category
Categories (5, object): [very bad, bad, medium, good, very good]
# 根据值排序
df.sort_values(by="grade")
Out[133]:
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
画图
读写数据,csv,hdf5,Excel,数据库等
# 写入数据csv
df.to_csv('foo.csv')
# 读取数据csv
pd.read_csv('foo.csv')
# 写、读hdf5数据
df.to_hdf('foo.h5','df')
pd.read_hdf('foo.h5','df')
# 读写Excel
df.to_excel('foo.xlsx', sheet_name='Sheet1')
pd.read_excel('foo.xlsx', 'Sheet1', index_col=None, na_values=['NA'])