python数据清洗案例_python数据清洗与准备

7.1处理缺失值

对于数值型数据,pandas使用浮点数NaN(not a number 来表示缺失值)。我们称NaN为容易检测到的缺失值:

import numpy as np

import pandas as pd

from pandas import Series,DataFrame

string_data = pd.Series(['aardvark','artichoke',np.nan,'avocado'])

string_data.isnull()

0 False

1 False

2 True

3 False

dtype: bool

在pandas中我们采用了R语言中的编程惯例,将缺失值成为NA,意思是not available(不可用)。

Python内建的None值在对象数组中也被当作NA处理:

string_data[0] = None

string_data.isnull()

0 True

1 False

2 True

3 False

dtype: bool

过滤缺失值

虽然你可以使用pandas.isnull和布尔值索引手动地过滤缺失值,但dropna在过滤缺失值时是非常有用的。

在Series上使用dropna,它会返回Series中所有的非空数据及其索引值。

from numpy import nan as NA

data = pd.Series([1,NA,3.5,NA,7])

data.dropna()

0 1.0

2 3.5

4 7.0

dtype: float64

这等价于

data[data.notnull()]

当处理DataFrame对象时,你可能想要删除全部为NA或包含有NA的行或列

dropna默认情况下会删除包含缺失值的行。

传入how = 'all'时,将删除所有值均为NA的行。(此时默认axis = 0)

传入参数axis = 1和how= 'all',将删除所有值均为NA的列。

如果想保留包含一定数量观察值的行,用thresh参数:df.dropna(thresh = 2)向上保留两行

补全缺失值

大多数情况下主要使用fillna方法来补全缺失值,调用它时可以使用一个是 常数 来替代缺失值。

在调用fillna时使用字典,你可以为不同 列 设定不同的 填充值。

fillna返回的是一个新的对象,但你也可以修改已经存在的对象,inplace 修改被调用的对象,而不是生成一个备份 df.fillna(0,inplace = True)

用于重建索引的相同的插值方法也可以用于fillna,method:插值方法,如果没有其他参数,默认是‘ffill’,limit:用于前向或后向填充时最大的填充范围df.fillna(method = 'ffill',limit = 2)

你也可以将Series的平均值或中位数用于填充缺失值:Series.fillna(Series.mean())

c74606486daf

还有一种比较常用数学上的朗格朗日插值法以及牛顿插值法,见博客。

7.2数据转换

由于各种原因,DataFrame中会出现重复行。

DataFrame的duplicated方法返回的是一个布尔值Series,这个Series反映的是每行是否存在 重复 情况。

drop_duplicates返回的是DataFrame,内容是duplicated返回数组中为False的部分(相当于去除重复行后的部分)。

data = pd.DataFrame({'k1':['one','two']*3 + ['two'],'k2':[1,1,2,3,3,4,4]})

data.duplicated()

0 False

1 False

2 False

3 False

4 False

5 False

6 True

dtype: bool

#

data.drop_duplicates()

k1 k2

0 one 1

1 two 1

2 one 2

3 two 3

4 one 3

5 two 4

这些方法默认都是对 列 进行操作。你可以指定数据的任何子集来检测是否有重复。假设我们有一个额外的列,并想基于‘k1’列去除重复值:data.drop_duplicates(['k1'])

duplicated 和 drop_duplicates默认都是保留第一个观测到的值,传入参数keep = ‘last’将会返回最后一个 :data.drop_duplicates(['k1','k2'],keep = 'last')

使用 函数 或 映射 进行数据转换

对于许多数据集,你可能希望基于DataFrame中的数组、列或列中的数值进行一些转换。

data = pd.DataFrame({'food':['bacon','pulled pork','bacon', 'Pastrami','corned beef','Bacon',

'pastrami','honey ham','nova lox'], 'oneces':[4,3,12,6,7.5,8,3,5,6]})

meat_to_animal = {'bacon':'pig', 'pulled pork':'pig', 'pastrami':'cow', 'corned beef':'pig',

'honey ham':'pig', 'nova lox':'salmon'}

lowercased = data['food'].str.lower()

data['animal'] = lowercased.map(meat_to_animal)

data

food oneces animal

0 bacon 4.0 pig

1 pulled pork 3.0 pig

2 bacon 12.0 pig

3 Pastrami 6.0 cow

4 corned beef 7.5 pig

5 Bacon 8.0 pig

6 pastrami 3.0 cow

7 honey ham 5.0 pig

8 nova lox 6.0 salmon

Series 的map方法接收一个函数或包含映射关系的字典型对象,可以传入一个能够完成所有工作的函数:

data['food'].map(lambda x: meat_to_animal[x.lower()])

0 pig

1 pig

2 pig

3 cow

4 pig

5 pig

6 cow

7 pig

8 salmon

Name: food, dtype: object

替代值

使用fillna填充缺失值是通用值替换的特殊案例。

map 可以用来修改一个对象中的子集的值,但是replace提供了更为简单灵活的实现

-999可能是缺失值的标识。如果要使用NA来替代,可以使用replace方法生成新的Series(除非你传入了inplace= True

data = pd.Series([1.,-999,2.,-999,-1000.,3.])

data.replace(-999,np.nan)

0 1.0

1 NaN

2 2.0

3 NaN

4 -1000.0

5 3.0

dtype: float64

如果你想一次替代多个值,传入一个列表和一个替代值:data.replace([-999,-1000],np.nan)

要将不同的值替换成对应不同的值,传入替代值的列data.replace([-999,-1000],[np.nan,0])

参数也可以通过字典传递:data.replace({-999:np.nan,-1000:0})

data.replace 方法与data.str.replace 方法不同的,data.str.replace是对 字符串 按元素替代

重命名轴索引

和Series一样,你可以通过函数或某种形式的映射对 轴标签 进行类似的转换,生成新的且带有不同标签的对象。你也可以在不生成新的的数据结构的情况下修改轴。

与Series类似,轴索引也有一个map方法,transform = lambda x: x[:4].upper(),然后赋值给index,修改DataFrame data.index = data.index.map(transform)

data = pd.DataFrame(np.arange(12).reshape((3,4)),

index = ['Ohio','Colorado','New York'],

columns = ['one','two','three','four'])

data

one two three four

Ohio 0 1 2 3

Colorado 4 5 6 7

New York 8 9 10 11

transform = lambda x: x[:4].upper()

data.index.map(transform)

Index(['OHIO', 'COLO', 'NEW '], dtype='object')

#也可以赋值给index,修改DataFrame

data.index = data.index.map(transform)

data

one two three four

OHIO 0 1 2 3

COLO 4 5 6 7

NEW 8 9 10 11

如果你想创建数据集转换后的版本,并且不修改原有的数据集,一个有用的方法就是rename data.rename(index = str.title,columns = str.upper)

rename 可以结合字典型对象使用,为轴标签的子集提供新的值(修改轴标签)

data.rename(index = {'OHIO':'INDIADA'},columns = {'three':'peekaboo'})

如果你想修改原有的数据集,传入inplace = True

data.rename(index = {'OHIO':'INDIADA'},inplace = True)

离散化和分箱

假设你有一组人群的数据,你想将他们分组,放入离散的年龄框中cats = pd.cut(ages,bins)

#将这些年龄分为18-25,26-35,36-60,以及61以上等若干组。你可以使用pandas中的cut:

#(区间左开右闭)

ages = [20,22,25,27,21,23,37,31,61,45,41,32]

bins = [18,25,35,60,100]

cats = pd.cut(ages,bins)

cats

[(18, 25], (18, 25], (18, 25], (25, 35], (18, 25], ..., (25, 35], (60, 100], (35, 60], (35, 60], (25, 35]]

Length: 12

Categories (4, interval[int64]): [(18, 25] < (25, 35] < (35, 60] < (60, 100]]

你看到的输出描述了由pandas.cut计算出的箱。你可以把它当做一个表示箱名的字符串数组;它在内部包含一个categories(类别)数组,他制定了不同的类别名称以及codes属性中的categories类别:

cats.codes

array([0, 0, 0, 1, 0, 0, 2, 1, 3, 2, 2, 1], dtype=int8)

cats.categories

IntervalIndex([(18, 25], (25, 35], (35, 60], (60, 100]],

closed='right',

dtype='interval[int64]')

#value_counts是对箱数量的计数

pd.value_counts(cats)

(18, 25] 5

(35, 60] 3

(25, 35] 3

(60, 100] 1

dtype: int64

与数学区间的符号一样,区间默认左开右闭。你可以通过传递right = False来改变那一边是封闭的:pd.cut(ages,[18,26,36,61,100],right = False)

你也可以通过向 labels 选项传递一个列表或数组来传入自定义的箱名:

如果你根据cut 整数个的箱来代替显式的箱边,pandas将根据数组中的最大值和最小值计算出等长的箱。pd.cut(data,4,precision=2)# 将十进制精度限制在两位。

qcut 函数,基于样本分位数进行分箱。你可以使用 qcut 获得等长(箱内数据量相等)的箱。

data = np.random.randn(1000)#正态分布

cats = pd.qcut(data,4)#切成4份

cats

[(0.018, 0.679], (0.018, 0.679], (0.679, 2.951], (-0.684, 0.018], (-2.96, -0.684], ..., (-0.684, 0.018], (-0.684, 0.018], (-2.96, -0.684], (0.018, 0.679], (-2.96, -0.684]]

Length: 1000

Categories (4, interval[float64]): [(-2.96, -0.684] < (-0.684, 0.018] < (0.018, 0.679] < (0.679, 2.951]]

pd.value_counts(cats)

(0.679, 2.951] 250

(0.018, 0.679] 250

(-0.684, 0.018] 250

(-2.96, -0.684] 250

dtype: int64

与cut类似,你可以传入自定义的分位数(0合1之间的数据,包括边)pd.qcut(data,[0,0.1,0.5,0.9,1.])

检测和过滤异常值

假设你想找出一列中绝对值大于三的值 col = data[2] col[np.abs(col)>3]

要选出所有大于3小于-3的行,你可以对布尔值DataFrame使用any方法

data[(np.abs(data) > 3).any(1) ]

这里eny()用于判断给定的iterable可迭代参数是否全部为False,只要有一个为True,则返回True。(这样使布尔序列的索引,与原索引对象的索引匹配。)

将绝对值大于三的值根据其正负转换成3或-3 data[np.abs(data)>3] = np.sign(data)*3

置换和随机抽样

使用numpy.random.permutation 对DataFrame中的Series或行进行置换(随机重排序)是非常方便的。

在调用permutation时根据你想要的轴长度可以产生一个表示新顺序的整数数组:

整数数组可以用在基于iloc的索引和等价的take函数中:

df = pd.DataFrame(np.arange(5*4).reshape((5,4)))

0 1 2 3

0 0 1 2 3

1 4 5 6 7

2 8 9 10 11

3 12 13 14 15

4 16 17 18 19

sampler = np.random.permutation(5)#array([0, 1, 3, 4, 2])

df.take(sampler)

0 1 2 3

0 0 1 2 3

1 4 5 6 7

3 12 13 14 15

4 16 17 18 19

2 8 9 10 11

df.iloc[sampler]

0 1 2 3

0 0 1 2 3

1 4 5 6 7

3 12 13 14 15

4 16 17 18 19

2 8 9 10 11

要选出一个不含有替代值的随机子集,可以使用Series和DataFrame中的sample方法

df.sample(n=3)

0 1 2 3

1 4 5 6 7

0 0 1 2 3

3 12 13 14 15

要生成一个带有替代值的样本(允许有重复选择),将replace = True传入sample方法:

draws = choices.sample(n=10,replace = True)

choices = pd.Series([5,7,-1,6,4])

draws = choices.sample(n=10,replace = True)

4 4

0 5

1 7

3 6

1 7

4 4

1 7

4 4

0 5

4 4

dtype: int64

计算指标/虚拟变量

如果DataFrame中的一列有k个不同的值,则可以衍生一个k列的值为1和0的矩阵或DataFrame。

pandas有一个get_dummies 函数用于实现该功能,pd.get_dummies(df['key'])

df = pd.DataFrame({'key':['b','b','a','c','a','b'],

'data':range(6)}

key data

0 b 0

1 b 1

2 a 2

3 c 3

4 a 4

5 b 5

pd.get_dummies(df['key'])

a b c

0 0 1 0

1 0 1 0

2 1 0 0

3 0 0 1

4 1 0 0

5 0 1 0

pd.get_dummies(df['data'])

0 1 2 3 4 5

0 1 0 0 0 0 0

1 0 1 0 0 0 0

2 0 0 1 0 0 0

3 0 0 0 1 0 0

4 0 0 0 0 1 0

5 0 0 0 0 0 1

#你可能想在指标DataFrame的列上后加入前缀,然后与其他数据合并。在get_dummies方法中有一个前缀参数prefix用于实现该功能:

pd.get_dummies(df['key'],prefix = 'key')

df_with_dummy = df[['data']].join(dummies)

data key_a key_b key_c

0 0 0 1 0

1 1 0 1 0

2 2 1 0 0

3 3 0 0 1

4 4 1 0 0

5 5 0 1 0

这里的join函数前面的索引项是一个列表,这样导出的是一个DataFrame,否则生成Series,与join函数大小不一致,会报错。

(!!!重点:书中205页案例)

字符串对象方法

一个逗号分隔的字符串可以使用split方法拆分成多块 val ='a,b, guide' val.split(',')

split常和strip一起使用,用于清除空格(包括换行) pieces = [x.strip() for x in val.split(',')]

这些字符串可以使用加法与两个冒号分隔符连接在一起:first,second,third = pieces

first + '::' + second+ '::' + third ---- 'a::b::guide'

在字符串‘::’的join方法中传入一个列表或元组是一种更快的pythonic(python风格化)的方法 '::'.join(pieces)

使用和关键字in 是检验子字符串的最佳方法,index和find也能实现同样的功能

请注意find和index 的区别:index在字符串没有找到时抛出一个异常,而find返回的是-1 'guide' in val val.index(',') val.find(':')

count返回的是某个特定的子字符串在字符串中出现的次数 val.count(',')

replace 将用另一种模式替代一种模式。也可用于传入空字符来删除某个模式val.replace(',','::') val.replace(',','')

c74606486daf

正则表达式

一种在文本中灵活查找或匹配字符串模式的方法。Python内建的re 模块适用于将正则表达式应用到字符串上的库。

re模块有三的主题:模式匹配、替代、拆分

描述一个或多个空白字符的正则表达式是 \s+

你可以使用re.compile自行编译,形成一个可复用的正则表达式对象:re.compile('\s+')

re.IGNORECASE使正则表达式不区分大小写 re.compile(pattern,flags = re.IGNORECASE)

如果想获得 一个所有匹配正则表达式的列表,使用findall方法 regex.findall(text)

search匹配对象只能返回 模式在字符串中起始和结束的位置

match如果在起始位置没有匹配到,则返回None

sub会返回 一个新的字符串,原字符串中的模式会被新的字符串替代:

c74606486daf

pandas中的向量化字符串函数

部分向量字符串方法列表

c74606486daf

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值