热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

7.1处理缺失值对于数值型数据,pandas使用浮点数NaN(notanumber来表示缺失值)。我们称NaN为容易检测到的缺失值&#x

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计算出的箱。你可以把它当做一个表示箱名的字符串数组&#xff1b;它在内部包含一个categories&#xff08;类别&#xff09;数组&#xff0c;他制定了不同的类别名称以及codes属性中的categories类别&#xff1a;

cats.codes

array([0, 0, 0, 1, 0, 0, 2, 1, 3, 2, 2, 1], dtype&#61;int8)

cats.categories

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

closed&#61;&#39;right&#39;,

dtype&#61;&#39;interval[int64]&#39;)

#value_counts是对箱数量的计数

pd.value_counts(cats)

(18, 25] 5

(35, 60] 3

(25, 35] 3

(60, 100] 1

dtype: int64

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

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

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

qcut 函数&#xff0c;基于样本分位数进行分箱。你可以使用 qcut 获得等长&#xff08;箱内数据量相等&#xff09;的箱。

data &#61; np.random.randn(1000)#正态分布

cats &#61; 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类似&#xff0c;你可以传入自定义的分位数&#xff08;0合1之间的数据&#xff0c;包括边&#xff09;pd.qcut(data,[0,0.1,0.5,0.9,1.])

检测和过滤异常值

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

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

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

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

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

置换和随机抽样

使用numpy.random.permutation 对DataFrame中的Series或行进行置换&#xff08;随机重排序&#xff09;是非常方便的。

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

整数数组可以用在基于iloc的索引和等价的take函数中&#xff1a;

df &#61; 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 &#61; 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

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

df.sample(n&#61;3)

0 1 2 3

1 4 5 6 7

0 0 1 2 3

3 12 13 14 15

要生成一个带有替代值的样本&#xff08;允许有重复选择&#xff09;&#xff0c;将replace &#61; True传入sample方法&#xff1a;

draws &#61; choices.sample(n&#61;10,replace &#61; True)

choices &#61; pd.Series([5,7,-1,6,4])

draws &#61; choices.sample(n&#61;10,replace &#61; 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个不同的值&#xff0c;则可以衍生一个k列的值为1和0的矩阵或DataFrame。

pandas有一个get_dummies 函数用于实现该功能&#xff0c;pd.get_dummies(df[&#39;key&#39;])

df &#61; pd.DataFrame({&#39;key&#39;:[&#39;b&#39;,&#39;b&#39;,&#39;a&#39;,&#39;c&#39;,&#39;a&#39;,&#39;b&#39;],

&#39;data&#39;: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[&#39;key&#39;])

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[&#39;data&#39;])

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的列上后加入前缀&#xff0c;然后与其他数据合并。在get_dummies方法中有一个前缀参数prefix用于实现该功能&#xff1a;

pd.get_dummies(df[&#39;key&#39;],prefix &#61; &#39;key&#39;)

df_with_dummy &#61; df[[&#39;data&#39;]].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函数前面的索引项是一个列表&#xff0c;这样导出的是一个DataFrame&#xff0c;否则生成Series&#xff0c;与join函数大小不一致&#xff0c;会报错。

&#xff08;!!!重点:书中205页案例&#xff09;

字符串对象方法

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

split常和strip一起使用&#xff0c;用于清除空格&#xff08;包括换行&#xff09; pieces &#61; [x.strip() for x in val.split(&#39;,&#39;)]

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

first &#43; &#39;::&#39; &#43; second&#43; &#39;::&#39; &#43; third ---- &#39;a::b::guide&#39;

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

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

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

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

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

c74606486daf

正则表达式

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

re模块有三的主题&#xff1a;模式匹配、替代、拆分

描述一个或多个空白字符的正则表达式是 \s&#43;

你可以使用re.compile自行编译&#xff0c;形成一个可复用的正则表达式对象&#xff1a;re.compile(&#39;\s&#43;&#39;)

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

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

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

match如果在起始位置没有匹配到&#xff0c;则返回None

sub会返回 一个新的字符串&#xff0c;原字符串中的模式会被新的字符串替代&#xff1a;

c74606486daf

pandas中的向量化字符串函数

部分向量字符串方法列表

c74606486daf



推荐阅读
author-avatar
itsima
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有