image
干净整洁的数据是后续进行研究和分析的基础. 数据科学家们会花费大量的时间来清理数据集, 毫不夸张地说, 数据清洗会占据他们 80% 的工作时间, 而真正用来分析数据的时间只占到 20% 左右.
所以, 数据清洗到底是在清洗些什么?
通常来说, 你所获取到的原始数据不能直接用来分析, 因为它们会有各种各样的问题, 如包含无效信息, 列名不规范, 格式不一致, 存在重复值, 缺失值, 异常值等.....
本文会给大家介绍如何用 Python 中自带的 Pandas 和 NumPy 库进行数据清洗. 在正式讲解之前, 先简单介绍一下这两个非常好用的库.
Pandas 的名称来自于 P anel data 和 Python 数据分析 data analysis , 是 Python 的一个数据分析包, 最初由 AQR Capital Management 于 2008 年 4 月开发, 被作为金融数据分析工具, 为时间序列分析提供了很好的支持, 并于 2009 年底开源出来.
NumPy 是 Numeric Python 的缩写, 是 Python 的一种开源的数值计算扩展, 可用来存储和处理大型矩阵 matrix , 比 Python 自身的嵌套列表结构要高效的多, 提供了许多高级的数值编程工具, 如: 矩阵数据类型, 矢量处理, 以及精密的运算库, 专为进行严格的数字处理而产生.
目录
一, 了解数据
二, 清洗数据
去除不需要的行, 列
重新命名列
重新设置索引
用字符串操作规范列
用函数规范列
删除重复数据
填充缺失值
三, 总结
[注] 为了清晰直观地展示数据清洗操作, 本文会用到几个不同的数据集, 重点是方法的讲解.
[工具] Python 3
一, 了解数据
拿到一个全新的数据集, 应该从哪里入手?
没错, 我们需要先了解数据, 看看它长什么样子. 这里用 tushare.pro 上面的日线行情数据进行展示, 以浦发银行 (600000.SH) 为例. 常用的方法和属性如下:
- **.head()**
- **.tail()**
- **.shape**
- **.columns**
- **.info()**
- **.describe()**
- **.value_counts()**
首先, 获取数据:
- importpandasaspd
- importnumpyasnp
- importmatplotlib.pyplotasplt
- importtushareasts
- pd.set_option('display.max_columns',100)# 设置显示数据的最大列数, 防止出现省略号..., 导致数据显示不全
- pd.set_option('expand_frame_repr',False)# 当列太多时不自动换行
- pro = ts.pro_api()
- df = pro.daily(ts_code='600000.SH', start_date='20190401', end_date='20190430')
**.head() ** 查看前 n 行数据, 默认值是 5
- df.head()
- Out[1]:
- ts_codetrade_dateopenhighlowclosepre_closechangepct_chgvolamount
- 0 600000.SH20190430 11.7012.0911.7011.9711.480.494.26831234747.381466714.710
- 1 600000.SH20190429 11.3511.5411.3411.4811.320.161.4134385869.38442046.727
- 2 600000.SH20190426 11.4311.5611.2811.3211.54-0.22-1.9064424695.81485267.261
- 3 600000.SH20190425 11.5611.6911.4811.5411.62-0.08-0.6885408761.29473973.527
- 4 600000.SH20190424 11.7611.7711.5111.6211.70-0.08-0.6838382011.08444929.313
**.tail() ** 查看后 n 行数据, 默认值是 5
- df.tail()
- Out[2]:
- ts_codetrade_dateopenhighlowclosepre_closechangepct_chgvolamount
- 16 600000.SH20190408 11.7911.9611.6511.7211.710.010.0854778703.73920513.531
- 17 600000.SH20190404 11.5511.7111.5411.7111.500.211.8261752325.27876099.547
- 18 600000.SH20190403 11.3711.5411.3411.5011.440.060.5245502710.29575799.446
- 19 600000.SH20190402 11.5011.5211.4111.4411.440.000.0000467147.10534896.810
- 20 600000.SH20190401 11.3611.5211.2911.4411.280.161.4184706374.05808657.530
**.shape ** 查看数据维数
- df.shape
- Out[3]: (21, 11)
**.columns ** 查看所有列名
- df.columns
- Out[4]:
- Index(['ts_code','trade_date','open','high','low','close','pre_close',
- 'change','pct_chg','vol','amount'],
- dtype='object')
**.info() ** 查看索引, 数据类型和内存信息
- df.info()
- RangeIndex:21entries,0to20
- Data columns (total11columns):
- ts_code21non-nullobject
- trade_date21non-nullobject
- open21non-nullfloat64
- high21non-nullfloat64
- low21non-nullfloat64
- close21non-nullfloat64
- pre_close21non-nullfloat64
- change21non-nullfloat64
- pct_chg21non-nullfloat64
- vol21non-nullfloat64
- amount21non-nullfloat64
- dtypes: float64(9),object(2)
- memory usage:1.9+ KB
**.describe() ** 查看每列数据的基本统计值, 包括计数值, 均值, 标准差, 最小最大值, 1/4,1/2,3/4 分位数.
- df.describe()
- Out[7]:
- openhighlowclosepre_closechangepct_chgvolamount
- count21.00000021.00000021.00000021.00000021.00000021.00000021.0000002.100000e+01 2.100000e+01
- mean11.63047611.77761911.52428611.63714311.6042860.0328570.2962525.734931e+05 6.704836e+05
- std0.2153480.2289300.1848400.2075120.2067990.1932131.6710992.333355e+05 2.792896e+05
- min11.35000011.52000011.28000011.32000011.280000-0.300000-2.4979002.627369e+05 3.017520e+05
- 25% 11.47000011.56000011.41000011.48000011.470000-0.060000-0.5199004.102754e+05 4.739735e+05
- 50% 11.56000011.75000011.48000011.54000011.5400000.0000000.0000005.027103e+05 5.757994e+05
- 75% 11.76000011.99000011.65000011.72000011.7100000.1000000.8396007.050917e+05 8.161270e+05
- max12.02000012.20000011.88000012.01000012.0100000.4900004.2683001.234747e+06 1.466715e+06
.value_counts() 查看 Series 对象的唯一值和计数值
- df['close'].value_counts(dropna=False)
- Out[8]:
- 11.482
- 11.472
- 11.712
- 11.542
- 11.912
- 11.442
- 11.721
- 11.951
- 11.701
- 11.321
- 11.491
- 12.011
- 11.621
- 11.501
- 11.971
- Name:close, dtype:int64
如果上面这些操作还不够直观的话, 就作图看看, 需要先导入 Python 可视化库 matplotlib , 为了规范代码书写, 统一写在了最前面.
1 直方图
- df['close'].plot(kind='hist', rot=0)
- plt.show()
image
2 箱型图
- df.boxplot(column='close',by='ts_code', rot=0)
- plt.show()
image
3 散点图
- df.plot(kind='scatter', x='close', y='pre_close', rot=0)
- plt.show()
image
二, 清洗数据
了解数据集之后, 我们就可以开始对数据集进行清洗了, 前面提到通常要处理的问题有包含无效信息, 列名不规范, 格式不一致, 存在重复值, 缺失值, 异常值等, 下面我们一个一个来看.
01
去除不需要的行, 列
在分析一个数据集的时候, 很多信息其实是用不到的, 因此, 需要去除不必要的行或列. 这里以 CSV 文件为例, 在导入的时候就可以通过设置 pd.read_csv() 里面的参数来实现这个目的.
先来感受一下官方文档中给出的详细解释, 里面的参数是相当的多, 本文只介绍比较常用的几个, 感兴趣的话, 可以好好研究一下文档, 这些参数还是非常好用的, 能省去很多导入后整理的工作.
image
[ header ] 默认 header=0, 即将文件中的 0 行作为列名和数据的开头, 但有时候 0 行的数据是无关的, 我们想跳过 0 行, 让 1 行作为数据的开头, 可以通过将 header 设置为 1 来实现.
[ usecols ] 根据列的位置或名字, 如 [0,1,2] 或['a', 'b', 'c'], 选出特定的列.
[ nrows ] 要导入的数据行数, 在数据量很大, 但只想导入其中一部分时使用.
如果你对 Python 编程感兴趣, 那么记得来小编的 Python 学习扣群: 1017759557, 这里有资源共享, 技术解答, 大家可以在一起交流 Python 编程经验, 还有小编整理的一份 Python 学习教程, 希望能帮助大家更好的学习 python.
获取数据:
从 NYC OpenData 网站下载 CSV 格式原始数据
image
数据样本如下:
image
导入数据, 只选取前 100 行和特定几列.
- subset_columns= ['Job #','Doc #','Borough','Initial Cost','Total Est. Fee']
- df = pd.read_csv('文件路径', nrows=100, usecols=subset_columns)
- df.head()
- Out[15]:
- Job# Doc # Borough Initial Cost Total Est. Fee
- 04202917941QUEENS$2000.00$100.00
- 14202918011QUEENS$15000.00$151.50
- 23406441281BROOKLYN$44726.00$234.00
- 34216854391QUEENS$0.00$243.00
- 44216779742QUEENS$105000.00$1275.60
再看一下将 header 设置为 1 的效果, 但这里其实不需要这么做, 因为 0 行数据是有用的.
- df= pd.read_csv('文件路径', nrows=100, header=1)
- df.head()
- Out[15]:
- 04202917941QUEENS$2000.00$100.00
- 14202918011QUEENS$15000.00$151.50
- 23406441281BROOKLYN$44726.00$234.00
- 34216854391QUEENS$0.00$243.00
- 44216779742QUEENS$105000.00$1275.60
如果在数据导入之后, 还想删除某些行和列, 可以用 **.drop() ** 方法.
先创建一个列表 list, 把不需要的列名放进去, 再调用 .drop() 方法, 参数 axis 为 1 时代表列, 为 0 时代表行, 参数 inplace=True 表示不创建新的对象, 直接对原始对象进行修改. 这里我们删除前两列.
- to_drop= ['Job #','Doc #']
- df.drop(to_drop, axis=1, inplace=True)
- df.head()
- Out[22]:
- Borough Initial Cost Total Est. Fee
- 0QUEENS$2000.00$100.00
- 1QUEENS$15000.00$151.50
- 2BROOKLYN$44726.00$234.00
- 3QUEENS$0.00$243.00
- 4QUEENS$105000.00$1275.60
- 02
重新命名列
当原始数据的列名不好理解, 或者不够简洁时, 可以用 .rename() 方法进行修改. 这里我们把英文的列名改成中文, 先创建一个字典, 把要修改的列名定义好, 然后调用 rename() 方法.
- new_names = {
- 'Borough':'区','Initial Cost':'初始成本','Total Est. Fee':'总附加费用'
- }
- df.rename(columns=new_names, inplace=True)
- df.head()
- Out[23]:
区 初始成本 总附加费用
- 0 QUEENS$2000.00$100.00
- 1 QUEENS$15000.00$151.50
- 2 BROOKLYN$44726.00$234.00
- 3 QUEENS$0.00$243.00
- 4 QUEENS$105000.00$1275.60
- 03
重新设置索引
数据默认的索引是从 0 开始的有序整数, 但如果想把某一列设置为新的索引, 可以用 .set_index() 方法实现, 在示例中我们把 "区" 这列设置为新索引.
- df.set_index('区', inplace=True)
- df.head()
- Out[24]:
初始成本 总附加费用
区
- QUEENS$2000.00$100.00
- QUEENS$15000.00$151.50
- BROOKLYN$44726.00$234.00
- QUEENS$0.00$243.00
- QUEENS$105000.00$1275.60
- 04
用字符串操作规范列
字符串 str 操作是非常实用的, 因为列中总是会包含不必要的字符, 常用的方法如下:
- **lower()**
- **upper()**
- **capitalize()**
- **replace()**
- **strip()**
- **split()**
- **get()**
- **contains()**
- **find()**
str.lower() 是把大写转换成小写, 同理, str.upper() 是把小写转换成大写, 将示例中用大写字母表示的索引转换成小写, 效果如下:
- df.index = df.index.str.lower()
- df.head()
- Out[25]:
初始成本 总附加费用
区
- queens$2000.00$100.00
- queens$15000.00$151.50
- brooklyn$44726.00$234.00
- queens$0.00$243.00
- queens$105000.00$1275.60
str.capitalize() 设置首字母大写
- df.index = df.index.str.capitalize()
- df.head()
- Out[26]:
初始成本 总附加费用
区
- Queens$2000.00$100.00
- Queens$15000.00$151.50
- Brooklyn$44726.00$234.00
- Queens$0.00$243.00
- Queens$105000.00$1275.60
**str.replace('
去掉, 替换成空字符.
- df['初始成本'] = df['初始成本'].str.replace('$','')
- df['总附加费用'] = df['总附加费用'].str.replace('$','')
- df.head()
- Out[27]:
初始成本 总附加费用
区
- Queens2000.00100.00
- Queens15000.00151.50
- Brooklyn44726.00234.00
- Queens0.00243.00
- Queens105000.001275.60
**str.strip() ** 去除字符串中的头尾空格, 以及 \ n \t
- df['初始成本'] = '' + df['初始成本']
- df['初始成本'][0]
- Out[28]: '2000.00'
- df['初始成本'] = df['初始成本'].str.strip()
- df['初始成本'][0]
- Out[29]: '2000.00'
**str.split('x') ** 使用字符串中的'x' 字符作为分隔符, 将字符串分隔成列表. 这里将列中的值以 '.'进行分割, 效果如下:
- df['总附加费用'] = df['总附加费用'].str.split('.')
- df.head()
- Out[30]:
初始成本 总附加费用
区
- Queens2000.00[100,00]
- Queens15000.00[151,50]
- Brooklyn44726.00[234,00]
- Queens0.00[243,00]
- Queens105000.00[1275,60]
**str.get() ** 选取列表中某个位置的值. 接着上面分割后的结果, 我们用 str.get(0) 取出列表中前一个位置的数值, 生成新的一列 "总附加费用_整数", 即取出金额中的整数部分.
- df['总附加费用_整数'] = df['总附加费用'].str.get(0)
- df.head()
- Out[31]:
初始成本 总附加费用 总附加费用_整数
区
- Queens2000.00[100,00]100
- Queens15000.00[151,50]151
- Brooklyn44726.00[234,00]234
- Queens0.00[243,00]243
- Queens105000.00[1275,60]1275
**str.contains() ** 判断是否存在某个字符, 返回的是布尔值. 这里判断一下 "总附加费用_整数" 列中是否包含字符'0'.
- df['总附加费用_整数'].str.contains('0')
- Out[33]:
区
- QueensTrue
- QueensFalse
- BrooklynFalse
- QueensFalse
- QueensFalse
str.find() 检测字符串中是否包含子字符串 str, 如果是, 则返回该子字符串开始位置的索引值. 示例中的'0'字符最开始出现的位置是 1.
- df['总附加费用_整数'][0]
- Out[13]: '100'
- df['总附加费用_整数'][0].find('0')
- Out[14]: 1
学完基本的字符串操作方法, 我们来看一下如何结合 NumPy 来提高字符串操作的效率.
获取数据, 这里我们用一个新的数据集, 下载链接如下, 里面包含两个 CSV 文件和一个 txt 文件:
- https://github.com/realpython/python-data-cleaning
- 1 BL-Flickr-Images-Book.CSV
- 2 olympics.CSV
- 3 university_towns.txt
导入 CSV 文件1, 先观察一下 "Place of Publication" 这一列.
- df = pd.read_csv('文件路径')
- df['Place of Publication'].head(10)
- Out[38]:
- 0London
- 1London; Virtue & Yorston
- 2London
- 3London
- 4London
- 5London
- 6London
- 7pp.40. G. Bryan & Co: Oxford,1898
- 8London]
- 9London
- Name: PlaceofPublication, dtype:object
我们发现, 这一列中的格式并不统一, 比如 1 行中的 London; Virtue & Yorston,London 后面的部分我们不需要, 还有 7 行的 pp. 40. G. Bryan & Co: Oxford, 1898, 有效信息只是 Oxford.
再用 .tail(10) 方法观察这一列的最后十行:
- df['Place of Publication'].tail(10)
- Out[39]:
- 8277New York
- 8278London
- 8279New York
- 8280London
- 8281Newcastle-upon-Tyne
- 8282London
- 8283Derby
- 8284London
- 8285Newcastle upon Tyne
- 8286London
- Name: PlaceofPublication, dtype:object
我们发现, 8281 行的 Newcastle-upon-Tyne 中间有连字符, 但 8285 行却没有, 这些都是要解决的格式不规范的问题.
为了清洗这一列, 我们可以将 Pandas 中的 .str() 方法与 NumPy 的 np.where 函数相结合, np.where 函数是 Excel 的 IF()宏的矢量化形式, 它的语法如下:
>>> np.where(condition,then,else)
如果 condition 条件为真, 则执行 then , 否则执行 else . 这里的 condition 条件可以是一个类数组的对象, 也可以是一个布尔表达式, 我们也可以利用 np.where 函数嵌套多个条件进行矢量化计算和判断.
- >>> np.where(condition1, x1,
- np.where(condition2, x2,
- np.where(condition3, x3, ...)))
下面的这个实例, 就是同时嵌套两个条件解决上面提到的那两个字符串问题. 思路是, 如果字符串里面包含'London', 就用'London'代替, 这样可以去除其他冗余信息, 否则, 如果字符串里面包含'Oxford', 则用'Oxford'代替, 同时如果字符串里面包含符号'-', 则用空格代替.
- pub = df['Place of Publication']
- london = pub.str.contains('London')
- oxford = pub.str.contains('Oxford')
- df['Place of Publication'] = np.where(london,'London',
- np.where(oxford,'Oxford',
- pub.str.replace('-',' ')))
打印出前十行和后十行, 结果如下, 可以和整理前的数据进行对比.
- df['Place of Publication'].head(10)
- Out[42]:
- 0London
- 1London
- 2London
- 3London
- 4London
- 5London
- 6London
- 7Oxford
- 8London
- 9London
- Name: PlaceofPublication, dtype:object
- df['Place of Publication'].tail(10)
- Out[43]:
- 8277New York
- 8278London
- 8279New York
- 8280London
- 8281Newcastle upon Tyne
- 8282London
- 8283Derby
- 8284London
- 8285Newcastle upon Tyne
- 8286London
- Name: PlaceofPublication, dtype:object
- 05
用函数规范列
在某些情况下, 数据不规范的情况并不局限于某一列, 而是更广泛地分布在整个表格中. 因此, 自定义函数并应用于整个表格中的每个元素会更加高效. 用 applymap() 方法可以实现这个功能, 它类似于内置的 map() 函数, 只不过它是将函数应用于整个表格中的所有元素.
我们打开文件 txt 文件3, 先观察一下数据:
- $ head Datasets/univerisity_towns.txt
- Alabama[edit]
- Auburn (Auburn University)[1]
- Florence (University of North Alabama)
- Jacksonville (Jacksonville State University)[2]
- Livingston (University of West Alabama)[2]
- Montevallo (University of Montevallo)[2]
- Troy (Troy University)[2]
- Tuscaloosa (University of Alabama, Stillman College, Shelton State)[3][4]
- Tuskegee (Tuskegee University)[5]
- Alaska[edit]
观察发现, 数据格式有如下特点:
州 A[edit]
城市 A(大学)
城市 B(大学)
州 B[edit]
城市 A(大学)
城市 B(大学)
......
我们可以利用这一数据格式, 创建一个 (州, 市) 元组列表, 并将该列表转化成一个 DataFrame. 先创建一个列表, 列表中包含州和城市 (大学) 信息.
- university_towns = []
- withopen('D:/code/tushare interpret and tech team/python-data-cleaning-master/Datasets/university_towns.txt')asfile:
- forlineinfile:
- if'[edit]'inline:# 该行有[edit]
- state = line# 将改行信息赋值给 "州", 记住这个 "州", 直到找到下一个为止
- else:
- university_towns.append((state, line))# 否则, 改行为城市信息, 并且它们都属于上面的 "州"
- university_towns[:5]
- Out[44]:
- [('Alabama[edit]\n','Auburn (Auburn University)[1]\n'),
- ('Alabama[edit]\n','Florence (University of North Alabama)\n'),
- ('Alabama[edit]\n','Jacksonville (Jacksonville State University)[2]\n'),
- ('Alabama[edit]\n','Livingston (University of West Alabama)[2]\n'),
- ('Alabama[edit]\n','Montevallo (University of Montevallo)[2]\n')]
用 pd.DataFrame() 方法将这个列表转换成一个 DataFrame, 并将列设置为 "State" 和 "RegionName".Pandas 将接受列表中的每个元素, 并将元组左边的值传入 "State" 列, 右边的值传入 "RegionName" 列.
- towns_df = pd.DataFrame(university_towns, columns=['State','RegionName'])
- towns_df.head()
- Out[45]:
- State RegionName
- 0Alabama[edit]\n Auburn (Auburn University)[1]\n
- 1Alabama[edit]\n Florence (UniversityofNorth Alabama)\n
- 2Alabama[edit]\n Jacksonville (Jacksonville State University)[2]\n
- 3Alabama[edit]\n Livingston (UniversityofWest Alabama)[2]\n
- 4Alabama[edit]\n Montevallo (UniversityofMontevallo)[2]\n
接下来就要对列中的字符串进行整理,"State" 列中的有效信息是州名,"RegionName" 列中的有效信息是城市名, 其他的字符都可以删掉. 当然, 除了用之前提到的利用循环和 .str() 方法相结合的方式进行操作, 我们还可以选择用 applymap() 方法, 它会将传入的函数作用于整个 DataFrame 所有行列中的每个元素.
先定义函数 get_citystate(item) , 功能是只提取元素中的有效信息.
- defget_citystate(item):
- if'('initem:
- returnitem[:item.find('(')]
- elif'['initem:
- returnitem[:item.find('[')]
- else:
- returnitem
然后, 我们将这个函数传入 applymap() , 并应用于 towns_df, 结果如下:
- towns_df = towns_df.applymap(get_citystate)
- towns_df.head()
- Out[48]:
- State RegionName
- 0 Alabama Auburn
- 1 Alabama Florence
- 2 Alabama Jacksonville
- 3 Alabama Livingston
- 4 Alabama Montevallo
现在 towns_df 表格看起来是不是干净多了!
06
删除重复数据
重复数据会消耗不必要的内存, 在处理数据时执行不必要的计算, 还会使分析结果出现偏差. 因此, 我们有必要学习如何删除重复数据.
先看一个来自 DataCamp 的数据集, 调用 info()方法打印出每列数据的具体信息和内存信息, 共有 24092 行数据, 内存占用量是 753.0+ KB.
- tracks = billboard[['year','artist','track','time']]
- print(tracks.info())
- RangeIndex:24092entries,0to24091
- Data columns (total4columns):
- year24092non-nullint64
- artist24092non-nullobject
- track24092non-nullobject
- time24092non-nullobject
- dtypes: int64(1),object(3)
- memory usage:753.0+ KB
- None
下面调用 .drop_duplicates() 函数删除重复数据.
- In [11]: tracks_no_duplicates = tracks.drop_duplicates()
- ... print(tracks_no_duplicates.info())
- ...
- Int64Index:317entries,0to316
- Data columns (total4columns):
- year317non-nullint64
- artist317non-nullobject
- track317non-nullobject
- time317non-nullobject
- dtypes: int64(1),object(3)
- memory usage:12.4+ KB
- None
删完之后我们发现, 数据量减少到了 317 个, 内存占用缩减至 12.4+ KB.
07
填充缺失值
数据集中经常会存在缺失值, 学会正确处理它们很重要, 因为在计算的时候, 有些无法处理缺失值, 有些则在默认情况下跳过缺失值. 而且, 了解缺失的数据, 并思考用什么值来填充它们, 对做出无偏的数据分析至关重要.
同样是来自 DataCamp 的一个存在缺失值的数据集:
- In[3]:airquality.head(10)
- Out[3]:
- OzoneSolar.RWindTempMonthDay
- 0 41.0190.07.467 5 1
- 1 36.0118.08.072 5 2
- 2 12.0149.012.674 5 3
- 3 18.0313.011.562 5 4
- 4NaNNaN14.356 5 5
- 5 28.0NaN14.966 5 6
- 6 23.0299.08.665 5 7
- 7 19.099.013.859 5 8
- 8 8.019.020.161 5 9
- 9NaN194.08.669 5 10
以 "Ozone" 列为例, 我们可以调用 fillna() 函数, 用该列的均值 .mean() 填充 NaN 值.
- oz_mean = airquality.Ozone.mean()
- airquality['Ozone'] = airquality['Ozone'].fillna(oz_mean)
- print(airquality.head(10))
- Ozone Solar.R Wind Temp Month Day
- 041.000000190.07.46751
- 136.000000118.08.07252
- 212.000000149.012.67453
- 318.000000313.011.56254
- 443.195402NaN14.35655
- 528.000000NaN14.96656
- 623.000000299.08.66557
- 719.00000099.013.85958
- 88.00000019.020.16159
- 943.195402194.08.669510
三, 总结
了解如何进行数据清洗非常重要, 因为它是数据科学的重要组成部分. 好在 Python 提供了非常好用的 Pandas 和 NumPy 库来帮助我们清理数据集, 本文介绍的方法都是在实际中经常会用到的, 希望大家能牢记于心.
如果你对 Python 编程感兴趣, 那么记得来小编的 Python 学习扣群: 1017759557, 这里有资源共享, 技术解答, 大家可以在一起交流 Python 编程经验, 还有小编整理的一份 Python 学习教程, 希望能帮助大家更好的学习 python.
来源: http://www.jianshu.com/p/ee078fdde3a3