一 pandas简介
pandas是一个强大的Python数据分析的工具包, 是基于NumPy构建的
pandas的主要功能
- 具备对其功能的数据结构DateFrame Series
- 集成时间序列功能
- 提供丰富的数学运算和操作
- 灵活处理缺失数据
安装方法: pip install pandas
引用方法:import pandas as pd
二 pands的Series对象
1 Series 一维数据对象
Seriaes是一种类似于一位数组的对象, 由一组数据和一组与之相关的数据标签(索引)组成新的二维数组
创建方式:
pd.Series([4,7,-5,3]) pd.Series([4,7,-5,3], index=['a', 'b', 'c', 'd']) pd.Series({'a':1, 'b':2}) pd.Series(0, index=['a','b','c','d'])
获取值数组和索引数据: values属性和index属性
Series比较像列表(数组)和字典的结合体
2 Series使用特性
Series支持array的特性(下标):
- 从ndarray创建Series:Series(arr)
- 与标量运算: sr*2
- 两个Series运算: sr1+sr2
- 索引:sr[0], sr[[1,2,4]]
- 切片:sr[0:2]
- 通用函数:np.abs(sr)
- 布尔值过滤: sr[sr>0]
Series支持字典的特性(标签):
- 从字典创建Series: Series(dic)
- in运算: 'a' in sr
- 键索引:sr['a'], sr[['a','b', 'd']]
3 Series整数索引问题
整数索引的pandas对象往往会使新手抓狂的地方
例如:
- sr = pd.Series(np.arange(4.))
- sr[-1]
如果索引是整数类型,则根据整数进行下标获取值时总是面向标签的。
解决方法: loc属性(将索引解释为标签)和iloc属性(将索引解释为下标)
如:sr2.loc[10] sr2.iloc[-1]
4 Series数据对齐
例:
- sr1 = pd.Series([12,23,34], index=['c','a','d'])
- sr2 = pd.Series([11,20,10], index=['d', 'c', 'a'])
- sr1+sr2
pandas在进行两个Series对象的运算时,会按索引进行对齐然后计算
- a:33
- c:32
- d:45
如何使用结果再索引'b'处的值为11, 在索引‘d’处的值为34?
- 灵活的算术方法: add, sub, div, mul
- sr1.add(sr2, fill_value=0)
5 Series缺失值处理
缺失数据:使用NaN(Not a Number) 来表示缺失数据。其值等于np.nan。内置的None值也会被当做NaN处理
sr.isnull() Nan返回True
sr.notnull() Nan但会False
sr.dropna() 删除索引Nan
sr.fillna(0) 填充所有的nan
过滤缺失数据:sr.dropna() 活 sr[data.notnull()]
填充缺失数据:fillna(0)
三 Pandas之DataFrame-二维数据对象
DataFrame是一个表格型的数据结构, 含有一组有序的列。DataFrame可以被看做是由Series组成的字典,并且共用一个索引
创建方式:
pd.DataFrame({'one':[1,2,3,4], 'two':[4,3,2,1]}) pd.DataFrame({'one':pd.Series([1,2,3], index=['a','b','c']), 'two':pd.Series([1,2,3,4],index=['b','a','c','d'])})
csv文件读取与写入:
df.read_csv('filename.csv') df.to_csv()
DataFrame常用的属性:
index 获取索引 行索引
T 转置 行变成列 列变成行
columns 获取列索引
values 获取值数组
describe() 获取快速统计
DataFrame索引和切片:
索引:
- df[col] df[[c1,c2]] # 取列
- df.loc[index] # 取列
- df.loc[index, col] # 取元素
切片
- df[a:b] # 切行
- df.loc[:, a:b] # 切列
DataFrame是一个二维数据类型,所以有行索引和列索引。
DataFrame同样可以通过标签和位置两种方法进行索引和切片。
loc属性和iloc属性:
- 使用方法: 逗号隔开,前面是行索引, 后面是列索引
- 行/列索引部分可以是常规索引,切片,布尔索引,花式索引任意搭配
示例:
# 先取列再取行 df['one']['a'] # 推荐使用loc df.loc['a', 'one'] # 查看一行数据 dc.loc['a', :]
DataFrame数据对齐与缺失数据:
DataFrame对象在运算时, 同样会进行数据对齐, 其行索引和列索引分别对齐
DataFrame处理缺失数据的相关方法:
dropna(axis=0, where='any', ...) # 当行所有都是Nan才删除dropna(how='any') fillna() isnull() notnull()
四 pandas其他常用方法
常用函数
mean(axis=0, skipna=False) 对列(行)求平均数 sum(axis=1) 对列(行)求和 sort_index(axis, ..., ascending) 对列(行)索引排序 sort_values(by,axis, ascending) 安某一列(行)的值排序
reset_index(drop=true) 重新处理index NumPy的通用函数同样适用于pandas
五 pandas-时间对象处理
时间序列类型:
- 时间戳:特定时刻
- 固定时刻: 如2017年7月
- 时间间隔:起始时间-结束时间
Python标准库处理时间对象:datetime
灵活处理时间对象: dateutil
dateutil.parser.parse()
成组处理时间对象:pandas
pd.to_datetime()
生成时间范围:date_range
- start 开始时间
- end 结束时间
- periods 时间长度
- freq 时间频率, 默认为'D', 可选H(our), W(eek), B(usiness), S(emi0)M(onth), (min)T(es), S(econd), A(year)
pd.date_range('2010-01-01', '2010-5-1')
pandas-时间序列:
时间序列就是以时间对象为索引的Series或DataFrame
datetime对象作为索引时是存储在DatetimeIndex对象中的。
时间序列特殊功能:
- 传入“年”或“年月”作为切边方式
- 传入日期范围作为切片方式
- 丰富的函数支持: resample(), truncate()
六 pandas-文件处理
数据文件常用格式: csv(以某间隔符分割数据)
pandas读取文件: 从文件名,URL,文件对象中加载数据
read_csv 默认分隔符为逗号
read_table 默认分隔符为制表符
read_csv, read_table函数主要参数:
sep 指定分隔符,可用正则表达式如"s+" header=None 指定文件无列名 name 指定列名 index_col 指定某列为索引 skip_row 指定跳过某些行 na_values 指定某些字符串表示缺失值 parse_dates 指定某些列是否被解析为日期,类型布尔值或列表
pandas写入csv文件: to_csv函数:
sep 指定文件分隔符 na_rep 指定缺失值转换的字符串,默认为空字符串 header=False 不输出列名一行 index=False 不输出索引一列 cols 指定输出的列,传入列表
七 Pands实现数据清洗
处理丢失数据
有两种丢失数据:
- None
- np.nan(NaN)
1. None
None是Python自带的,其类型为python object。因此,None不能参与到任何计算中。
2. np.nan(NaN)
np.nan是浮点类型,能参与到计算中。但计算的结果总是NaN。
1) pandas中None与np.nan都视作np.nan
创建dataframe
import numpy as np import pandas as pd df = pd.DataFrame(data=np.random.randint(10, 50, size=(8,8))) df 0 1 2 3 4 5 6 7 0 29 36 36 30 43 17 20 33 1 43 21 49 19 30 33 49 10 2 11 44 13 45 20 10 29 35 3 10 34 45 12 29 26 10 15 4 11 11 49 15 48 26 49 36 5 26 45 44 28 42 33 43 45 6 29 46 42 30 45 15 29 24 7 28 23 26 28 29 15 18 32
将某些数组元素赋值为nan
df.iloc[1,3] = None df.iloc[2,2] = None df.iloc[4,2] = None df.iloc[6,7] = np.nan df 0 1 2 3 4 5 6 7 0 29 36 36.0 30.0 43 17 20 33.0 1 43 21 49.0 NaN 30 33 49 10.0 2 11 44 NaN 45.0 20 10 29 35.0 3 10 34 45.0 12.0 29 26 10 15.0 4 11 11 NaN 15.0 48 26 49 36.0 5 26 45 44.0 28.0 42 33 43 45.0 6 29 46 42.0 30.0 45 15 29 NaN 7 28 23 26.0 28.0 29 15 18 32.0
2) pandas处理空值操作
isnull()
notnull()
dropna()
: 过滤丢失数据 可以选择过滤的是行还是列(默认为行):axis中0表示行,1表示的列fillna()
: 填充丢失数据
#创建DataFrame,给其中某些元素赋值为nan df.notnull().all(axis=1) df[df.notnull().all(axis=1)] 0 1 2 3 4 5 6 7 0 29 36 36.0 30.0 43 17 20 33.0 3 10 34 45.0 12.0 29 26 10 15.0 5 26 45 44.0 28.0 42 33 43 45.0 7 28 23 26.0 28.0 29 15 18 32.0
3 填充函数 Series/DataFrame
fillna()
:value和method参数
可以选择前向填充还是后向填充, method 控制填充的方式 bfill ffill
df.fillna(method='ffill', axis=0) 0 1 2 3 4 5 6 7 0 29 36 36.0 30.0 43 17 20 33.0 1 43 21 49.0 30.0 30 33 49 10.0 2 11 44 49.0 45.0 20 10 29 35.0 3 10 34 45.0 12.0 29 26 10 15.0 4 11 11 45.0 15.0 48 26 49 36.0 5 26 45 44.0 28.0 42 33 43 45.0 6 29 46 42.0 30.0 45 15 29 45.0 7 28 23 26.0 28.0 29 15 18 32.0
# 检查哪些列存在空值 并对检查出的空值进行覆盖 df.isnull().any(axis=0) df.fillna(method='ffill', axis=0, inplace=True) df 0 1 2 3 4 5 6 7 0 29 36 36.0 30.0 43 17 20 33.0 1 43 21 49.0 30.0 30 33 49 10.0 2 11 44 49.0 45.0 20 10 29 35.0 3 10 34 45.0 12.0 29 26 10 15.0 4 11 11 45.0 15.0 48 26 49 36.0 5 26 45 44.0 28.0 42 33 43 45.0 6 29 46 42.0 30.0 45 15 29 45.0 7 28 23 26.0 28.0 29 15 18 32.0
八 Pands的高级操作
1、删除重复元素(数据清洗的一种方式)
使用duplicated()函数检测重复的行,返回元素为布尔类型的Series对象,每个元素对应一行,如果该行不是第一次出现,则元素为True
- keep参数:指定保留哪一重复的行数据
- 创建具有重复元素行的DataFrame
import numpy as np import pandas as pd from pandas import Series,DataFrame #创建一个df df = DataFrame(data=np.random.randint(0, 100, size=(8,4))) df #手动将df的某几行设置成相同的内容 df.iloc[2] = [66,66,66,66] df.iloc[4] = [66,66,66,66] df.iloc[7] = [66,66,66,66] # 使用duplicated查看所有重复元素行 df.duplicated(keep='first') 0 False 1 False 2 False 3 False 4 True 5 False 6 False 7 True dtype: bool # 删除重复元素的行 # 发生重复的行索引 index = df.loc[df.duplicated(keep='last')].index df.drop(labels=index, axis=0)
使用drop_duplicates()函数删除重复的行
- drop_duplicates(keep='first/last'/False)
df.drop_duplicates(keep="last") 0 1 2 3 0 65 41 7 32 1 15 17 13 38 3 95 96 53 79 5 54 81 49 78 6 13 58 0 26 7 66 66 66 66
2. 映射
1) replace()函数:替换元素
使用replace()函数,对values进行映射操作
Series替换操作
- 单值替换
- 普通替换
- 字典替换(推荐)
- 多值替换
- 列表替换
- 字典替换(推荐)
- 参数
- to_replace:被替换的元素
DataFrame替换操作
- 单值替换
- 普通替换: 替换所有符合要求的元素:to_replace=15,value='e'
- 按列指定单值替换: to_replace={列标签:替换值} value='value'
- 多值替换
- 列表替换: to_replace=[] value=[]
字典替换(推荐) to_replace={to_replace:value,to_replace:value}
# 单值替换 df.replace(to_replace=66, value=666) 0 1 2 3 0 65 41 7 32 1 15 17 13 38 2 66 66 66 66 3 95 96 53 79 4 66 66 66 66 5 54 81 49 78 6 13 58 0 26 7 66 66 66 66
# 多值替换 df.replace(to_replace=[66, 25], value=[63, 2255]) 0 1 2 3 0 65 41 7 32 1 15 17 13 38 2 63 63 63 63 3 95 96 53 79 4 63 63 63 63 5 54 81 49 78 6 13 58 0 26 7 63 63 63 63
# key列索引,value要替换的值 df.replace(to_replace={2:66}, value=666) 0 1 2 3 0 65 41 7 32 1 15 17 13 38 2 66 66 666 66 3 95 96 53 79 4 66 66 666 66 5 54 81 49 78 6 13 58 0 26 7 66 66 666 66
注意:DataFrame中,无法使用method和limit参数
2) map()函数:新建一列 , map函数并不是df的方法,而是series的方法
- map()可以映射新一列数据
- map()中可以使用lambd表达式
-
map()中可以使用方法,可以是自定义的方法
eg:map({to_replace:value})
- 注意 map()中不能使用sum之类的函数,for循环
# 新增一列:给df中,添加一列,该列的值为中文名对应的英文名 dic = { 'name':['jay', 'tom', 'jay'], 'salary':[10000,15000,10000] } df = DataFrame(data=dic) df name salary 0 jay 10000 1 tom 15000 2 jay 10000
# 定制一个映射关系表 dic = { 'jay':'周杰伦', 'tom':'张三' } df['c_name'] = df['name'].map(dic) df name salary c_name 0 jay 10000 周杰伦 1 tom 15000 张三 2 jay 10000 周杰伦
#### map当做一种运算工具,至于执行何种运算,是由map函数的参数决定的(参数:lambda,函数)
- 使用自定义函数
#超过10000部分的钱缴纳50%的税 def after_sal(s): if s < 10000: return s else: return s-(s-10000)*0.5 df['after_sal']=df['salary'].map(after_sal) df name salary c_name after_sal 0 jay 10000 周杰伦 10000.0 1 tom 15000 张三 12500.0 2 jay 10000 周杰伦 10000.0
- 使用lambda表达式
df['after_sal']=df['salary'].map(lambda s:s-(s-10000)*0.5)
注意:并不是任何形式的函数都可以作为map的参数。只有当一个函数具有一个参数且有返回值,那么该函数才可以作为map的参数
3. 使用聚合操作对数据异常值检测和过滤
使用df.std()函数可以求得DataFrame对象每一列的标准差
# 创建一个1000行3列的df 范围(0-1),求其每一列的标准差 df = DataFrame(data=np.random.random(size=(1000,3)), columns=['A','B','C']) A B C 0 0.623677 0.296882 0.180331 1 0.151164 0.838745 0.074804 2 0.810686 0.278847 0.632431 3 0.949126 0.836832 0.363521 ............................. # 对df应用筛选条件,去除标准差太大的数据:假设过滤条件为 C列数据大于两倍的C列标准差 value_std = df['C'].std() * 2 df['C'] <= value_std df.loc[df['C'] <= value_std ]
4. 排序
使用.take()函数排序
- take()函数接受一个索引列表,用数字表示,使得df根据列表中索引的顺序进行排序
- eg:df.take([1,3,4,2,5])
可以借助np.random.permutation()函数随机排序
# 对列进行乱序 df.take([2,1,0],axis=1) C B A 0 0.227520 0.448755 0.946236 1 0.651939 0.880108 0.395235 2 0.917283 0.914232 0.584911 3 0.837992 0.267088 0.821250 4 0.489001 0.435002 0.901875
# np.random.permutation(x)可以生成x个从0-(x-1)的随机数列 random_df = df.take(np.random.permutation(1000), axis=0).take(np.random.permutation(3), axis=1) random_df[0:100] C B A 290 0.712080 0.287919 0.798695 188 0.148218 0.500367 0.334136 335 0.789687 0.518180 0.951512 617 0.196197 0.740249 0.065249 ............................ # 随机抽样 # 当DataFrame规模足够大时,直接使用np.random.permutation(x)函数,就配合take()函数实现随机抽样
5. 数据分类处理【重点】
数据聚合是数据处理的最后一步,通常是要使每一个数组生成一个单一的数值。
数据分类处理:
- 分组:先把数据分为几组
- 用函数处理:为不同组的数据应用不同的函数以转换数据
- 合并:把不同组得到的结果合并起来
数据分类处理的核心:
- groupby()函数
- groups属性查看分组情况
- eg: df.groupby(by='item').groups
分组
df = DataFrame({'item':['Apple','Banana','Orange','Banana','Orange','Apple'], 'price':[4,3,3,2.5,4,2], 'color':['red','yellow','yellow','green','green','green'], 'weight':[12,20,50,30,20,44]}) df
# 使用groupby实现分组 df.groupby(by='item', axis=0).groups {'Apple': Int64Index([0, 5], dtype='int64'), 'Banana': Int64Index([1, 3], dtype='int64'), 'Orange': Int64Index([2, 4], dtype='int64')} # 计算出苹果的平均价格 df.groupby(by='item',axis=0).mean()['price'][0] # 先取出列再运算节省计算成本 df.groupby(by='item')['price'].mean()[0] # 按颜色查看各种颜色的水果的平均价格 color_price = df.groupby(by='color')['price'].mean() dic = color_price.to_dict() df['color_mean_price'] = df['color'].map(dic) df item price color weight mean_price color_mean_price 0 Apple 4.0 red 12 3.00 4.000000 1 Banana 3.0 yellow 20 2.75 3.000000 2 Orange 3.0 yellow 50 3.50 3.000000 3 Banana 2.5 green 30 2.75 2.833333 4 Orange 4.0 green 20 3.50 2.833333 5 Apple 2.0 green 44 3.00 2.833333 # 汇总:将各种颜色水果的平均价格和df进行汇总 mean_price = df.groupby(by='item')['price'].mean() dic = mean_price.to_dict() df['mean_price'] = df['item'].map(dic) df item price color weight mean_price 0 Apple 4.0 red 12 3.00 1 Banana 3.0 yellow 20 2.75 2 Orange 3.0 yellow 50 3.50 3 Banana 2.5 green 30 2.75 4 Orange 4.0 green 20 3.50 5 Apple 2.0 green 44 3.00
6 高级数据聚合
使用groupby分组后,也可以使用transform和apply提供自定义函数实现更多的运算
- df.groupby('item')['price'].sum() <==> df.groupby('item')['price'].apply(sum)
- transform和apply都会进行运算,在transform或者apply中传入函数即可
- transform和apply也可以传入一个lambda表达式
#使用apply函数求出水果的平均价格 def fun(s): sum = 0 for i in s: sum+=s return sum/s.size df.groupby(by='item')['price'].apply(fun) 0 4.0 1 3.0 2 3.0 3 2.5 4 4.0 5 2.0 Name: price, dtype: float64 #使用transform函数求出水果的平均价格 df.groupby(by='item')['price'].transform(fun) df item price color weight mean_price color_mean_price 0 Apple 4.0 red 12 3.00 4.000000 1 Banana 3.0 yellow 20 2.75 3.000000 2 Orange 3.0 yellow 50 3.50 3.000000 3 Banana 2.5 green 30 2.75 2.833333 4 Orange 4.0 green 20 3.50 2.833333 5 Apple 2.0 green 44 3.00 2.833333