pandas的基本使用
- pandas三剑客
# 财务部门
import numpy as np
# 业务部门
import pandas as pd
# UI部门
import matplotlib.pyplot as plt
# 导入两种数据类型
from pandas import Series, DataFrame
Series数组
- 一维数组:一组【有序的】,【数据类型相同】的集合
- Series是一种【类似】于【一维数组】的对象,由下面两个部分组成:
- values:一组数据(ndarray类型)
- index:相关的数据索引标签
Series的创建
- 格式
Series(data=None, index=None, dtype=None, name=None, copy=False, fastpath=False)
两种创建方式: - 由列表或numpy数组创建
默认索引为0到N-1的整数型索引
#列表创建
l1 = [1,2,3,4,5]
#如果没有设置索引,会自动以隐式索引替代
s1 = Series(l1) ==>
0 1
1 2
2 3
3 4
4 5
dtype: int64
#ndarray创建
arr2 = np.random.randint(0,10,size=4)
s3 = Series(arr2) ==>
0 0
1 3
2 1
3 3
dtype: int32
#列表作为索引(副本),array作为值创建(引用)
#由ndarray创建的是引用,而不是副本。对Series元素的改变也会改变原来的ndarray对象中的元素。(列表没有这种情况)
data = np.random.randint(0,100,size=3)
index = ["python","java","php"]
s = Series(data=data, index=index)
s ==>
python 18
java 94
php 39
dtype: int32
- 由字典创建
name_dic = {
"tom":19,
"mery":20,
"lucy":19,
"jery":21
}
#默认使用字典的键
Series(data=name_dic) ==>
jery 21
lucy 19
mery 20
tom 19
dtype: int64
#使用定义的键
Series(data=name_dic,index=["tom","mery"]) ==>
tom 19
mery 20
dtype: int64
Series的索引和切片
-
索引
可以使用中括号取单个索引(此时返回的是元素类型),或者中括号里一个列表取多个索引(此时返回的仍然是一个Series类型)。分为显示索引和隐式索引:(1) 显式索引:
- 使用index中的元素作为索引值
- 使用.loc[](推荐)
注意,此时是闭区间
(2) 隐式索引:
- 使用整数作为索引值
- 使用.iloc[](推荐)
注意,此时是半开区间
dic = {
"name":"tom",
"address":"beijing",
"score":100
}
# 【注意】sereis对象也会强制统一数据类型
s1 = Series(data=dic) ==>
address beijing
name tom
score 100
dtype: object
#显示访问
# 字典的方式访问
s1["name"] ==>'tom'
# Series特有的访问形式
# 为的是统一访问形式
s1.loc["name"] ==>'tom'
#隐式访问
s1[1] ==>'tom'
s1.iloc[1] ==>'tom'
# 【重点】
# loc[key]
# iloc[index]
- 切片
- 但凡是隐式索引访问的,都是左闭右开
- 但凡是显示索引访问的,都是左闭右闭区间
#显示索引切片
s1.loc["address":"name"] ==>
address beijing
name tom
dtype: object
#隐式索引切片
# 使用隐式索引切片
s1.iloc[0:2] ==>
address beijing
name tom
dtype: object
Series的属性和方法
- 属性
可以把Series看成一个定长的有序字典,可以通过shape,size,index,values,name,dtype等得到series的属性
s ==>
语文 150
数学 130
英语 140
理综 300
dtype: int64
#shape属性
s.shape ==> (4,)
#size属性
s.size ==>4
#index属性
s.index ==>
Index(['语文', '数学', '英语', '理综'], dtype='object')
#values属性
s.values ==>
array([150, 130, 140, 300], dtype=int64)
#name属性(得到列索引值)
#dtype属性
s.dtype ==>dtype('int64')
## 拓展:如何研究一个陌生的类型??
type(s.index) ==>pandas.core.indexes.base.Index
from pandas.core.indexes.base import Index
使用help(Index)或者Index?? 来查帮助文档
pd.Index(["A","B","C"]) ==>
Index(['A', 'B', 'C'], dtype='object')
- 方法
- 常用的:
- value_counts
- sort_values
- sort_index
- isnull().any()
- s[s.isnull()]
- s[s.notnull()]
- s.head()
- s.tail()
- 常用的:
#value_counts 统计Series中,每一个值出现的次数,一般统计的是离散值
data = ["tom","jack","tom","tom","jack","lucy","tom","jack"]
s = Series(data) ==>
0 tom
1 jack
2 tom
3 tom
4 jack
5 lucy
6 tom
7 jack
dtype: object
#value_counts
s.value_counts() ==>
tom 4
jack 3
lucy 1
dtype: int64
#unique()去重函数,查看一个Series中存在哪些值
s.unique() ==>
array(['tom', 'jack', 'lucy'], dtype=object)
#可以使用head(),tail()分别查看前n个和后n个值
s.head(2) ==>
0 tom
1 jack
dtype: object
s.tail(2) ==>
6 tom
7 jack
dtype: object
#对值和索引排序
s ==>
0 88
1 27
2 96
3 24
4 47
5 1
6 36
7 63
8 1
9 34
dtype: int32
#值排序
s1 = s.sort_values() ==>
5 1
8 1
3 24
1 27
9 34
6 36
4 47
7 63
0 88
2 96
dtype: int32
#索引排序(索引需要是数字类型)
s1.sort_index() ==>
0 88
1 27
2 96
3 24
4 47
5 1
6 36
7 63
8 1
9 34
dtype: int32
- 使用Bool_list访问数组对象
BOOL型的列表可以读取列表数据,True对应的值就会返回,False对应的值就放弃
s1 ==>
0 2.0
1 1.0
2 NaN
3 4.0
4 NaN
dtype: float64
#普通版
bool_list = [True, False,True, False, False]
s1[bool_list] ==>
0 2.0
2 NaN
dtype: float64
# 获取空值的数据
s1.loc[s1.isnull()] ==>
2 NaN
4 NaN
dtype: float64
# 过滤掉空值
s1.loc[s1.notnull()]
0 2.0
1 1.0
3 4.0
dtype: float64
Series的运算
- 适用于numpy的数组运算也适用于Series
# 和一个数运算
s = Series(data=np.array([1,2,3,4,5]))
s + 8 ==>
0 9
1 10
2 11
3 12
4 13
dtype: int32
- Series之间的运算
-
在运算中自动对齐不同索引的数据
-
如果索引不对应,则补NaN
-
pandas的空值和任何数运算,都得到np.nan
np.nan + 10000 ==> nan
-
s1 = Series(data=np.array([1,2,3,4,5]), index=list("ABCDE"))
s2 = Series(data=np.array([10,20,30,40,50]), index=list("BCDEF"))
s1 + s2 ==>
A NaN
B 12.0
C 23.0
D 34.0
E 45.0
F NaN
dtype: float64
#注意:要想保留所有的index,则需要使用
add() 加
sub() 减
mul() 乘
div() 除
s1.add(s2, fill_value=0) ==>
A 1.0
B 12.0
C 23.0
D 34.0
E 45.0
F 50.0
dtype: float64
DataFrame
- 概念
DataFrame是一个【表格型】的数据结构,可以看做是【由Series组成的字典】(共用同一个索引)。DataFrame由按一定顺序排列的多列数据组成。设计初衷是将Series的使用场景从一维拓展到多维。DataFrame既有行索引,也有列索引。- 行索引:index
- 列索引:columns
- 值:values(numpy的二维数组)
DataFrame的创建
最常用的方法是传递一个字典来创建。DataFrame以字典的键作为每一【列】的名称,以字典的值(一个数组)作为每一列。
此外,DataFrame会自动加上每一行的索引(和Series一样)。
同Series一样,若传入的列与字典的键不匹配,则相应的值为NaN。
# 1、字典创建
dic1 = {
"name":["jack","lucy","tom"],
"python":[100,98,99],
"java":[98,79,86],
"C":[68,98,87]
}
df1 = DataFrame(data=dic1) ==>
C java name python
0 68 98 jack 100
1 98 79 lucy 98
2 87 86 tom 99
# 2、列表数组创建
data = np.random.randint(0,100,size=(3,4))
index = list("ABC")
columns = list("abcd")
df2 = DataFrame(data=data, index=index, columns=columns) ==>
a b c d
A 87 33 63 71
B 79 62 7 28
C 58 74 11 49
# 3、读取外部excel表格
pd.read_excel(io, sheetname=0, header=0, skiprows=None, skip_footer=0, index_col=None, names=None, parse_cols=None, parse_dates=False, date_parser=None, na_values=None, thousands=None, convert_float=True, has_index_names=None, converters=None, dtype=None, true_values=None, false_values=None, engine=None, squeeze=False, **kwds)
df3 = pd.read_excel('data.xlsx', sheet_name=1)
#4、直接把一个Series转换成DataFrame
s = Series(data=np.random.randint(0,10,size=(5)), index=list("ABCDE"), name="python")
DataFrame(s) ==>
python
A 3
B 1
C 1
D 7
E 4
DataFrame的属性
DataFrame属性:values、columns、index、shape、dtypes
dic = {
"zhangsan":[150,150,150,300],
"lisi":[10,20,70,88]
}
df = DataFrame(data=dic, index=["chinese","math","english","lizong"]) ==>
lisi zhangsan
chinese 10 150
math 20 150
english 70 150
lizong 88 300
#df.dtypes
df.dtypes ==>
lisi int64
zhangsan int64
dtype: object
df.shape ==>(4, 2)
df.index ==>Index(['chinese', 'math', 'english', 'lizong'], dtype='object')
df.columns ==>Index(['lisi', 'zhangsan'], dtype='object')
df.size ==> 8
#拓展
分布直方图
df.plot(kind="bar")
DataFrame的索引
- 对列进行索引
- 通过类似字典的方式
- 通过属性的方式
可以将DataFrame的列获取为一个Series。返回的Series拥有原DataFrame相同的索引,且name属性也已经设置好了,就是相应的列名。
#创建
columns = ["python","java","name","address"]
data = np.random.randint(0,100,size=(5,4))
df = DataFrame(data=data, columns=columns) ==>
python java name address
0 28 26 93 60
1 40 45 96 26
2 69 18 71 64
3 45 46 55 0
4 85 23 51 95
#字典式访问
# 把DataFrame看成一个字典,每一个列标签,就是字典的键,对应的值就是这一列数据
df["address"]
#赋值
df["address"] = ["北京","上海","广州","深圳","武汉"]
df ==>
python java name address
0 22 70 36 北京
1 64 4 94 上海
2 89 36 46 广州
3 62 98 17 深圳
4 69 75 4 武汉
#使用属性访问
df.address
# 访问多列数据
df[["address","name"]]
- 对行进行索引
- 使用.ix[]来进行行索引
- 使用.loc[]加index来进行行索引
- 使用.iloc[]加整数来进行行索引
同样返回一个Series,series的index为datafrom的columns。
df ==>
python java name address
0 28 26 93 北京
1 40 45 96 上海
2 69 18 71 广州
3 45 46 55 深圳
4 85 23 51 武汉
#访问
df.loc[0] ==>
python 28
java 26
name 93
address 北京
Name: 0, dtype: object
#改变行索引
df.index = list("abcde") ==>
python java name address
a 28 26 93 北京
b 40 45 96 上海
c 69 18 71 广州
d 45 46 55 深圳
e 85 23 51 武汉
#多行访问
df.loc[["a","b"]]
#隐式访问
df.iloc[0] ==>
python 28
java 26
name 93
address 北京
Name: a, dtype: object
df.iloc[1]
- 对元素索引的方法
- 使用列索引 .loc[index,columns]
- 使用行索引(iloc[3,1]相当于两个参数;iloc[[3,3]] 里面的[3,3]看做一个参数)
- 使用values属性(二维numpy数组)
df ==>
python java name address
a 28 26 93 北京
b 40 45 96 上海
c 69 18 71 广州
d 45 46 55 深圳
e 85 23 51 武汉
#显式访问
df.loc["b","java"] ==>45
# 隐式访问
df.iloc[1,1] ==>45
# 使用DataFrame的values属性访问
df.values[1,1] ==>45
总结:
列访问 df[column]
行访问 df.loc[index]
元素访问 df.loc[index, column]
切片
- 【注意】 直接用中括号时:
- 索引表示的是列索引
- 切片表示的是行切片
- 行切片 df[index1:index2]
- 列切片 df.loc[:, column1:column2]
- 块切片 df.loc[index1:index2, column1:column2]
- 其他写法:间接获取,可能是个引用,也可能是一个副本
- read是没有问题的, write有可能有问题,因为很可能你操作的是一个副本对象
df ==>
python java name address
a 22 70 36 北京
b 64 4 94 上海
c 89 36 46 广州
d 62 98 17 深圳
e 69 75 4 武汉
#行切片
df["a":"b"] ==>
python java name address
a 28 26 93 北京
b 40 45 96 上海
#列切片
df.loc[:,"python":"java"] ==>
python java
a 28 26
b 40 45
c 69 18
d 45 46
e 85 23
#快切片
df.loc["c":"d","name":"address"] ==>
name address
c 71 广州
d 55 深圳
#间接访问
df1 = df.loc[["b","c"]]
df1["address"] ==>
b 上海
c 广州
Name: address, dtype: object
DataFrame的运算
- DataFrame之间的运算
同Series一样:
在运算中自动对齐相同索引的数据
如果索引不对应,则补NaN
#正常情况下
df1 = DataFrame(data=np.random.randint(0,10,size=(3,3)))
df2 = DataFrame(data=np.ones(shape=(3,3)))
display(df1, df2) ==>
0 1 2
0 7 5 2
1 9 7 4
2 8 4 4
0 1 2
0 1.0 1.0 1.0
1 1.0 1.0 1.0
2 1.0 1.0 1.0
df1 + df2 ==>
0 1 2
0 8.0 6.0 3.0
1 10.0 8.0 5.0
2 9.0 5.0 5.0
#不正常情况
df3 = DataFrame(data=np.ones(shape=(3,4)))
如果索引不对齐,会自动补充np.nan
df1 + df3
0 1 2 3
0 8.0 6.0 3.0 NaN
1 10.0 8.0 5.0 NaN
2 9.0 5.0 5.0 NaN
#使用add函数
df1.add(df3,fill_value=0)
0 1 2 3
0 8.0 6.0 3.0 1.0
1 10.0 8.0 5.0 1.0
2 9.0 5.0 5.0 1.0
- 其他操作函数
+ add()
- sub(), subtract()
* mul(), multiply()
/ truediv(), div(), divide()
// floordiv()
% mod()
** pow()
- Series与DataFrame之间的运算
- 使用Python操作符:以行为单位操作(参数必须是行),对所有行都有效。(类似于numpy中二维数组与一维数组的运算,但可能出现NaN)
- 使用pandas操作函数:
axis=0:以列为单位操作(参数必须是列),对所有列都有效。
axis=1:以行为单位操作(参数必须是行),对所有行都有效。
s = Series(data=np.ones(shape=4), index=list("ABCE"))
df = DataFrame(data=np.random.randint(0,10,size=(4,4)), index=list("ABCD"),columns=list("abcd"))
display(s, df) ==>
A 1.0
B 1.0
C 1.0
E 1.0
dtype: float64
a b c d
A 2 0 8 0
B 5 0 9 0
C 6 9 4 5
D 1 2 9 3
# 默认DataFrame与Series运算,是以列标签对齐
df + s ==>
A B C E a b c d
A NaN NaN NaN NaN NaN NaN NaN NaN
B NaN NaN NaN NaN NaN NaN NaN NaN
C NaN NaN NaN NaN NaN NaN NaN NaN
D NaN NaN NaN NaN NaN NaN NaN NaN
#axis="index" 设置以行索引对齐
df.add(s, axis="index") ==>
a b c d
A 3.0 1.0 9.0 1.0
B 6.0 1.0 10.0 1.0
C 7.0 10.0 5.0 6.0
D NaN NaN NaN NaN
E NaN NaN NaN NaN
#过滤空值
df1[df1.notnull().any(axis=1)]
a b c d
A 3.0 1.0 9.0 1.0
B 6.0 1.0 10.0 1.0
C 7.0 10.0 5.0 6.0
axis=0(0 == index 行):以列为单位操作(参数必须是列),对所有列都有效。 axis=1(1 == columns 列):以行为单位操作(参数必须是行),对所有行都有效。
【注意】fill_value在df和series之间运算时,不能使用
处理丢失数据NaN
- 有两种丢失数据:
- None
- np.nan(NaN)
- 区别:
- type(None)是NoneType对象类型,type(np.nan)是float类型
- None不能运算,np.nan可以运算
- 数据运算速度,nan明显高于None,计算不同数据类型求和时间
%timeit np.arange(1e5,dtype=xxx).sum()
- pandas中None与np.nan都视作np.nan,自动转化
pandas中None与np.nan的操作
- 判断函数
- isnull()
- notnull()
s =
A 28.0
B 23.0
C NaN
D 65.0
E 90.0
Name: a, dtype: float64
s.isnull().any() ==>True
# DataFrame中,any\all\sum\mean\std函数,需要指定方向
# 使用axis控制方向,可以查看行或列是否存在空值
df ==>
0 1 2
0 NaN 8 1
1 1.0 5 2
2 0.0 0 4
df.isnull().any(axis=1) ==>
0 True
1 False
2 False
dtype: bool
- 过滤函数 dropna()
df.dropna(axis=0, how=‘any’, thresh=None, subset=None, inplace=False)- axis 用于控制行或列
- how =any 默认是有一个空值,就过滤掉该行(列)
df ==>
a b c d e
A 66.0 51.0 31.0 NaN 6.0
B 34.0 NaN 93.0 NaN 34.0
C NaN NaN 100.0 NaN NaN
D 45.0 1.0 68.0 NaN 76.0
E 53.0 26.0 87.0 NaN NaN
df.dropna(axis=1, how="all") ==>删除d列数据
- 填充函数 Series/DataFrame fillna()
df.fillna(value=None, method=None, axis=None, inplace=False, limit=None, downcast=None, **kwargs)- value 指定一个特殊的值填充
- method 指定填充方式(上 ‘backfill’, 左’bfill’,右 ‘pad’,下 ‘ffill’, None)
- limit 限制填充次数
- axis=1表示横向填充, 默认填充到不能填充为止
df ==>
a b c d e
A 28.0 86.0 98.0 NaN 82.0
B 23.0 NaN 59.0 NaN 44.0
C NaN NaN 100.0 NaN NaN
D 65.0 87.0 84.0 NaN 57.0
E 90.0 36.0 97.0 NaN NaN
# 1. 指定一个特殊的值填充
# value 指要填充的固定值
df.fillna(value = 1000) ==>
a b c d e
A 28.0 86.0 98.0 1000.0 82.0
B 23.0 1000.0 59.0 1000.0 44.0
C 1000.0 1000.0 100.0 1000.0 1000.0
D 65.0 87.0 84.0 1000.0 57.0
E 90.0 36.0 97.0 1000.0 1000.0
# 2. 用相邻值填充
df.fillna(axis=1, method="ffill")
a b c d e
A 28.0 86.0 98.0 98.0 82.0
B 23.0 23.0 59.0 59.0 44.0
C NaN NaN 100.0 100.0 100.0
D 65.0 87.0 84.0 84.0 57.0
E 90.0 36.0 97.0 97.0 97.0
# 3limit限制填充次数
df.fillna(axis=0, method="backfill",limit=1)
- 指定索引标签来删除行(列)df.drop()
df.drop(labels, axis=0, level=None, inplace=False, errors=‘raise’)
df ==>
a b c d e
A 6.0 94.0 41.0 NaN 13.0
B 64.0 NaN 99.0 NaN 91.0
C 1.0 NaN 100.0 NaN NaN
D 12.0 43.0 98.0 NaN 89.0
E 35.0 71.0 49.0 NaN NaN
# 默认删除行,用列表指定行索引
df.drop(labels=["C"])
#删除列
df.drop(labels=["d","c"],axis=1)
# 删除全是空值的列
df.drop(labels=df.loc[:,df.isnull().all()].columns, axis=1)
# 删除包含空值的行
drop_index = df[df.isnull().any(axis=1)].index
df.drop(labels=drop_index)