查看原文
其他

【翻译】《利用Python进行数据分析·第2版》第7章(上)

SeanCheney Python爱好者社区 2019-04-07

作者:SeanCheney   Python爱好者社区专栏作者

简书专栏:https://www.jianshu.com/u/130f76596b02


前文传送门:

【翻译】《利用Python进行数据分析·第2版》第1章 准备工作

【翻译】《利用Python进行数据分析·第2版》第2章(上)Python语法基础,IPython和Jupyter

【翻译】《利用Python进行数据分析·第2版》第2章(中)Python语法基础,IPython和Jupyter

【翻译】《利用Python进行数据分析·第2版》第2章(下)Python语法基础,IPython和Jupyter

【翻译】《利用Python进行数据分析·第2版》第3章(上)Python的数据结构、函数和文件

【翻译】《利用Python进行数据分析·第2版》第3章(中)Python的数据结构、函数和文件

【翻译】《利用Python进行数据分析·第2版》第3章(下)Python的数据结构、函数和文件

【翻译】《利用Python进行数据分析·第2版》第4章(上)NumPy基础:数组和矢量计算

【翻译】《利用Python进行数据分析·第2版》第4章(中)NumPy基础:数组和矢量计算

【翻译】《利用Python进行数据分析·第2版》第4章(下)NumPy基础:数组和矢量计算

【翻译】《利用Python进行数据分析·第2版》第5章(上)pandas入门

【翻译】《利用Python进行数据分析·第2版》第5章(中)pandas入门

【翻译】《利用Python进行数据分析·第2版》第5章(下)pandas入门

【翻译】《利用Python进行数据分析·第2版》第6章(上) 数据加载、存储与文件格式

【翻译】《利用Python进行数据分析·第2版》第6章(中) 数据加载、存储与文件格式

【翻译】《利用Python进行数据分析·第2版》第6章(下) 数据加载、存储与文件格式


在数据分析和建模的过程中,相当多的时间要用在数据准备上:加载、清理、转换以及重塑。这些工作会占到分析师时间的80%或更多。有时,存储在文件和数据库中的数据的格式不适合某个特定的任务。许多研究者都选择使用通用编程语言(如Python、Perl、R或Java)或UNIX文本处理工具(如sed或awk)对数据格式进行专门处理。幸运的是,pandas和内置的Python标准库提供了一组高级的、灵活的、快速的工具,可以让你轻松地将数据规变为想要的格式。


如果你发现了一种本书或pandas库中没有的数据操作方式,请尽管在邮件列表或GitHub网站上提出。实际上,pandas的许多设计和实现都是由真实应用的需求所驱动的。


在本章中,我会讨论处理缺失数据、重复数据、字符串操作和其它分析数据转换的工具。下一章,我会关注于用多种方法合并、重塑数据集。


7.1 处理缺失数据


在许多数据分析工作中,缺失数据是经常发生的。pandas的目标之一就是尽量轻松地处理缺失数据。例如,pandas对象的所有描述性统计默认都不包括缺失数据。


缺失数据在pandas中呈现的方式有些不完美,但对于大多数用户可以保证功能正常。对于数值数据,pandas使用浮点值NaN(Not a Number)表示缺失数据。我们称其为哨兵值,可以方便的检测出来:


In [10]: string_data = pd.Series(['aardvark', 'artichoke', np.nan, 'avocado']) In [11]: string_data Out[11]: 0     aardvark 1    artichoke 2          NaN 3      avocado dtype: object In [12]: string_data.isnull() Out[12]: 0    False 1    False 2     True 3    False dtype: bool


在pandas中,我们采用了R语言中的惯用法,即将缺失值表示为NA,它表示不可用not available。在统计应用中,NA数据可能是不存在的数据或者虽然存在,但是没有观察到(例如,数据采集中发生了问题)。当进行数据清洗以进行分析时,最好直接对缺失数据进行分析,以判断数据采集的问题或缺失数据可能导致的偏差。


Python内置的None值在对象数组中也可以作为NA:


In [13]: string_data[0] = None In [14]: string_data.isnull() Out[14]: 0     True 1    False 2     True 3    False dtype: bool


pandas项目中还在不断优化内部细节以更好处理缺失数据,像用户API功能,例如pandas.isnull,去除了许多恼人的细节。表7-1列出了一些关于缺失数据处理的函数。


表7-1 NA处理方法


滤除缺失数据


过滤掉缺失数据的办法有很多种。你可以通过pandas.isnull或布尔索引的手工方法,但dropna可能会更实用一些。对于一个Series,dropna返回一个仅含非空数据和索引值的Series:


In [15]: from numpy import nan as NA In [16]: data = pd.Series([1, NA, 3.5, NA, 7]) In [17]: data.dropna() Out[17]: 0    1.0 2    3.5 4    7.0 dtype: float64


这等价于:


In [18]: data[data.notnull()] Out[18]: 0    1.0 2    3.5 4    7.0 dtype: float64


而对于DataFrame对象,事情就有点复杂了。你可能希望丢弃全NA或含有NA的行或列。dropna默认丢弃任何含有缺失值的行:


In [19]: data = pd.DataFrame([[1., 6.5, 3.], [1., NA, NA],   ....:                      [NA, NA, NA], [NA, 6.5, 3.]]) In [20]: cleaned = data.dropna() In [21]: data Out[21]:     0    1    2 0  1.0  6.5  3.0 1  1.0  NaN  NaN 2  NaN  NaN  NaN 3  NaN  6.5  3.0 In [22]: cleaned Out[22]:     0    1    2 0  1.0  6.5  3.0


传入how='all'将只丢弃全为NA的那些行:


In [23]: data.dropna(how='all') Out[23]:     0    1    2 0  1.0  6.5  3.0 1  1.0  NaN  NaN 3  NaN  6.5  3.0


用这种方式丢弃列,只需传入axis=1即可:


In [24]: data[4] = NA In [25]: data Out[25]:     0    1    2   4 0  1.0  6.5  3.0 NaN 1  1.0  NaN  NaN NaN 2  NaN  NaN  NaN NaN 3  NaN  6.5  3.0 NaN In [26]: data.dropna(axis=1, how='all') Out[26]:     0    1    2 0  1.0  6.5  3.0 1  1.0  NaN  NaN 2  NaN  NaN  NaN 3  NaN  6.5  3.0


另一个滤除DataFrame行的问题涉及时间序列数据。假设你只想留下一部分观测数据,可以用thresh参数实现此目的:


In [27]: df = pd.DataFrame(np.random.randn(7, 3)) In [28]: df.iloc[:4, 1] = NA In [29]: df.iloc[:2, 2] = NA In [30]: df Out[30]:          0         1         2 0 -0.204708       NaN       NaN 1 -0.555730       NaN       NaN 2  0.092908       NaN  0.769023 3  1.246435       NaN -1.296221 4  0.274992  0.228913  1.352917 5  0.886429 -2.001637 -0.371843 6  1.669025 -0.438570 -0.539741 In [31]: df.dropna() Out[31]:          0         1         2 4  0.274992  0.228913  1.352917 5  0.886429 -2.001637 -0.371843 6  1.669025 -0.438570 -0.539741 In [32]: df.dropna(thresh=2) Out[32]:          0         1         2 2  0.092908       NaN  0.769023 3  1.246435       NaN -1.296221 4  0.274992  0.228913  1.352917 5  0.886429 -2.001637 -0.371843 6  1.669025 -0.438570 -0.539741


填充缺失数据


你可能不想滤除缺失数据(有可能会丢弃跟它有关的其他数据),而是希望通过其他方式填补那些“空洞”。对于大多数情况而言,fillna方法是最主要的函数。通过一个常数调用fillna就会将缺失值替换为那个常数值:

In [33]: df.fillna(0) Out[33]:          0         1         2 0 -0.204708  0.000000  0.000000 1 -0.555730  0.000000  0.000000 2  0.092908  0.000000  0.769023 3  1.246435  0.000000 -1.296221 4  0.274992  0.228913  1.352917 5  0.886429 -2.001637 -0.371843 6  1.669025 -0.438570 -0.539741

若是通过一个字典调用fillna,就可以实现对不同的列填充不同的值:

In [34]: df.fillna({1: 0.5, 2: 0}) Out[34]:          0         1         2 0 -0.204708  0.500000  0.000000 1 -0.555730  0.500000  0.000000 2  0.092908  0.500000  0.769023 3  1.246435  0.500000 -1.296221 4  0.274992  0.228913  1.352917 5  0.886429 -2.001637 -0.371843 6  1.669025 -0.438570 -0.539741

fillna默认会返回新对象,但也可以对现有对象进行就地修改:


In [35]: _ = df.fillna(0, inplace=True) In [36]: df Out[36]:          0         1         2 0 -0.204708  0.000000  0.000000 1 -0.555730  0.000000  0.000000 2  0.092908  0.000000  0.769023 3  1.246435  0.000000 -1.296221 4  0.274992  0.228913  1.352917 5  0.886429 -2.001637 -0.371843 6  1.669025 -0.438570 -0.539741


对reindexing有效的那些插值方法也可用于fillna:


In [37]: df = pd.DataFrame(np.random.randn(6, 3)) In [38]: df.iloc[2:, 1] = NA In [39]: df.iloc[4:, 2] = NA In [40]: df Out[40]:          0         1         2 0  0.476985  3.248944 -1.021228 1 -0.577087  0.124121  0.302614 2  0.523772       NaN  1.343810 3 -0.713544       NaN -2.370232 4 -1.860761       NaN       NaN 5 -1.265934       NaN       NaN In [41]: df.fillna(method='ffill') Out[41]:          0         1         2 0  0.476985  3.248944 -1.021228 1 -0.577087  0.124121  0.302614 2  0.523772  0.124121  1.343810 3 -0.713544  0.124121 -2.370232 4 -1.860761  0.124121 -2.370232 5 -1.265934  0.124121 -2.370232 In [42]: df.fillna(method='ffill', limit=2) Out[42]:          0         1         2 0  0.476985  3.248944 -1.021228 1 -0.577087  0.124121  0.302614 2  0.523772  0.124121  1.343810 3 -0.713544  0.124121 -2.370232 4 -1.860761       NaN -2.370232 5 -1.265934       NaN -2.370232


只要有些创新,你就可以利用fillna实现许多别的功能。比如说,你可以传入Series的平均值或中位数:


In [43]: data = pd.Series([1., NA, 3.5, NA, 7]) In [44]: data.fillna(data.mean()) Out[44]: 0    1.000000 1    3.833333 2    3.500000 3    3.833333 4    7.000000 dtype: float64


表7-2列出了fillna的参考。


fillna函数参数


赞赏作者

Python爱好者社区历史文章大合集

Python爱好者社区历史文章列表(每周append更新一次)

福利:文末扫码立刻关注公众号,“Python爱好者社区”,开始学习Python课程:

关注后在公众号内回复“课程”即可获取:

小编的Python入门视频课程!!!

崔老师爬虫实战案例免费学习视频。

丘老师数据科学入门指导免费学习视频。

陈老师数据分析报告制作免费学习视频。

玩转大数据分析!Spark2.X+Python 精华实战课程免费学习视频。

丘老师Python网络爬虫实战免费学习视频。



    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存