查看原文
其他

福布斯系列之数据清洗(1) | Python数据分析项目实战

LEMON Python数据之道 2022-04-24

用Python进行数据分析项目实战之福布斯系列文章,目前已发布的相关文章如下:

  1. 福布斯系列之数据分析思路篇

  2. 福布斯系列之数据采集

  3. 福布斯系列之数据完整性检查 | Python数据分析项目实战

  4. 福布斯系列之补充数据收集 | Python数据分析项目实战

  5. Pandas数据处理实战:福布斯全球上市企业排行榜数据整理


1 前言

本文涉及细节比较多,代码呈碎片化,建议在电脑上查看,或者回复关键字获取代码来运行,效果会更佳

关键字附在本文中。

本文作为数据清洗的第一篇,将详细的描述福布斯全球上市企业2000强排行榜数据中2007年数据的处理过程。

通常,我们都希望自己拿到的数据是比较规范,看起来令人清爽的数据。

然而,实际上我们获得的信息或数据,会因为各种各样的原因,存在数据缺失、不准确、不规范等异常情况。

需要我们在进行数据分析之前进行预处理。

福布斯全球上市企业2000强排行榜数据,从2007年到2017年,各个年份的数据都存在一些不规范的地方。

从本文开始至接下来的几篇文章,将通过福布斯项目来进行数据清洗的项目实战,希望能给大家带来些收获。

本项目运行环境:

  • windows7

  • jupyter notebook

2 数据清洗的目的

将不规范的数据进行处理,包括:

  1. 替换NaN值

  2. 将字符串型数字转换为数字类型

  3. 将数字后面多余的字母等文字剔除

  4. 将公司和国家进行拆分

  5. 将国家名称进行统一

  6. 按列名将DataFrame重新排序

最终达到的效果如下:

数据清洗前

数据类型

  1. 年份                    int64

  2. 排名(Rank)              int64

  3. 公司名称(Company)        object

  4. 所在国家或地区(Country)     object

  5. 所在行业(Industry)       object

  6. 销售收入(Sales)          object

  7. 利润(Profits)          object

  8. 总资产(Assets)          object

  9. 市值(Market Vaue)     float64

  10. dtype: object

图1:

数据清洗后

数据类型

  1. Year               int64

  2. Rank               int64

  3. Company_cn_en     object

  4. Company_en        object

  5. Company_cn        object

  6. Country_cn_en     object

  7. Country_cn        object

  8. Country_en        object

  9. Industry_cn       object

  10. Industry_en       object

  11. Sales            float64

  12. Profits          float64

  13. Assets           float64

  14. Market_value     float64

  15. dtype: object

图2:

数据清洗后, sales、Profits、Assets及Market_value列的数据均为数字类型,方便后续分析时计算使用。

3 数据清洗的详细过程

  1. import pandas as pd

  2. import numpy as np

2007年的数据,原始数据的单位为十亿美元。

3.1 先查看数据的类型(dtype)和结构

  1. df_2007 = pd.read_csv('./data/data_forbes_2007.csv', encoding='gbk', thousands=',')

  2. print('the shape of DataFrame: ', df_2007.shape)

  3. print(df_2007.dtypes)

  4. df_2007.head(3)

  5. out:

  6. the shape of DataFrame:  (2000, 9)

  7. 年份                    int64

  8. 排名(Rank)              int64

  9. 公司名称(Company)        object

  10. 所在国家或地区(Country)     object

  11. 所在行业(Industry)       object

  12. 销售收入(Sales)          object

  13. 利润(Profits)          object

  14. 总资产(Assets)          object

  15. 市值(Market Vaue)     float64

  16. dtype: object

图1:

更新columns的命名

  1. column_update = ['Year', 'Rank', 'Company_cn_en', 'Country_cn_en',

  2.                 'Industry_cn', 'Sales', 'Profits', 'Assets', 'Market_value']

  3. df_2007.columns = column_update

图3:

3.2 将字符串转换为数字类型

通过前面的分析可看出,只有“Market_value”是数字类型,找出'Sales','Profits'及'Assets'中非数字的内容

  1. df_2007[df_2007['Sales'].str.contains('.*[A-Za-z]', regex=True)]

图4:

用replace()方法替换“Sales”列中含有字母的内容

  1. df_2007['Sales'] = df_2007['Sales'].replace('([A-Za-z])', '', regex=True)

查看替换后的结果

  1. df_2007.loc[[117,616,880], :]

图5:

查看“Assets”列中非数字的内容

  1. df_2007[df_2007['Assets'].str.contains('.*[A-Za-z]', regex=True)]

图6:

替换非数字的内容,以及替换千分位间隔符号

  1. # 将数字后面的字母进行替换

  2. df_2007['Assets'] = df_2007['Assets'].replace('([A-Za-z])', '', regex=True)

  3. # 千分位数字的逗号被识别为string了,需要替换

  4. df_2007['Assets'] = df_2007['Assets'].replace(',', '', regex=True)

  5. df_2007.loc[616, :]

  6. out:

  7. Year                       2007

  8. Rank                        617

  9. Company_cn_en    Inpex Holdings

  10. Country_cn_en            日本(JA)

  11. Industry_cn                  炼油

  12. Sales                     6.49

  13. Profits                  1.02 E

  14. Assets                   10.77

  15. Market_value              19.65

  16. Name: 616, dtype: object

发现“Profits”中有NaN值,需要先进行替换

  1. df_2007[pd.isnull(df_2007['Profits'])]

  2. # 将NaN值替换为0

  3. df_2007['Profits'].fillna(0, inplace=True)

  4. df_2007.loc[[958,1440,1544,1912], :]

图7-8:

将“Profits”列中非数字的内容进行替换,并查看替换后的结果

  1. df_2007['Profits'] = df_2007['Profits'].replace('([A-Za-z])', '', regex=True)

  2. df_2007.loc[[117,616,880], :]

图9:

将string类型的数字转换为数据类型,这里使用 pd.to_numeric() 方法

  1. df_2007['Sales'] = pd.to_numeric(df_2007['Sales'])

  2. df_2007['Profits'] = pd.to_numeric(df_2007['Profits'])

  3. df_2007['Assets'] = pd.to_numeric(df_2007['Assets'])

  4. df_2007.dtypes

  5. out:

  6. Year               int64

  7. Rank               int64

  8. Company_cn_en     object

  9. Country_cn_en     object

  10. Industry_cn       object

  11. Sales            float64

  12. Profits          float64

  13. Assets           float64

  14. Market_value     float64

  15. dtype: object

3.3 拆分"Company_cn_en"列

新生成两列,分别为公司英文名称和中文名称

  1. df_2007['Company_en'],df_2007['Company_cn'] = df_2007['Company_cn_en'].str.split('/', 1).str

  2. print(df_2007['Company_en'][:5])

  3. print(df_2007['Company_cn'] [-5:])

  4. df_2007.tail(3)

  5. out:

  6. 0           Citigroup

  7. 1     Bank of America

  8. 2        HSBC Holdings

  9. 3    General Electric

  10. 4      JPMorgan Chase

  11. Name: Company_en, dtype: object

  12. 1995    NaN

  13. 1996    NaN

  14. 1997    NaN

  15. 1998    NaN

  16. 1999    NaN

  17. Name: Company_cn, dtype: object

图10:

3.4 拆分"Country_cn_en"列

新生成两列,分别为国家中文名称和英文名称

  1. df_2007['Country_cn'],df_2007['Country_en'] = df_2007['Country_cn_en'].str.split('(', 1).str

  2. print(df_2007['Country_cn'][:5])

  3. print(df_2007['Country_en'][-5:])

  4. out:

  5. 0    美国

  6. 1    美国

  7. 2    英国

  8. 3    美国

  9. 4    美国

  10. Name: Country_cn, dtype: object

  11. 1995    US)

  12. 1996    US)

  13. 1997    US)

  14. 1998    SI)

  15. 1999    GE)

  16. Name: Country_en, dtype: object

由于国家的英文名称中,最后有半个括号,需要去除,用 Series.str.slice()方法

参数表示选取从开始到倒数第二个,即不要括号")"

  1. df_2007['Country_en'] = df_2007['Country_en'].str.slice(0,-1)

  2. df_2007.head(3)

考虑的中国的企业有区分为中国大陆,中国香港,中国台湾。

对应的国家英文名称也需要修改下。

  • 中国大陆:CN;

  • 中国香港:CN-HK;

  • 中国台湾:CN-TA。

  1. # 查找含“中国”的数据

  2. df_2007[df_2007['Country_cn'].str.contains('中国',regex=True)]

  3. # 替换并查看结果

  4. df_2007['Country_en'] = df_2007['Country_en'].replace(['HK.*','TA'],['CN-HK', 'CN-TA'],regex=True)

  5. df_2007[df_2007['Country_en'].str.contains('CN',regex=True)]

图11-12:

考虑到其他年份,公司所在行业有用英文名称展示的,这里添加一列英文的行业名称,但内容是空白

  1. df_2007['Industry_en'] = ''

  2. df_2007.tail(3)

3.5 将列名进行重新排序

  1. columns_sort = ['Year', 'Rank', 'Company_cn_en','Company_en',

  2.                'Company_cn', 'Country_cn_en', 'Country_cn',

  3.                'Country_en', 'Industry_cn', 'Industry_en',

  4.                'Sales', 'Profits', 'Assets', 'Market_value']

  5. # 按指定list重新将columns进行排序

  6. df_2007 = df_2007.reindex(columns=columns_sort)

  7. print(df_2007.shape)

  8. print(df_2007.dtypes)

  9. df_2007.head(3)

  10. out:

  11. (2000, 14)

  12. Year               int64

  13. Rank               int64

  14. Company_cn_en     object

  15. Company_en        object

  16. Company_cn        object

  17. Country_cn_en     object

  18. Country_cn        object

  19. Country_en        object

  20. Industry_cn       object

  21. Industry_en       object

  22. Sales            float64

  23. Profits          float64

  24. Assets           float64

  25. Market_value     float64

  26. dtype: object

图result:

4 总结

至此,将2007年的原始数据进行了初步处理,当然,在后续的分析过程中,可能还会有少量的处理。

经过数据清洗后,获得的数据信息相对来说比较规范,数据的质量较好,可以用来后续分析使用或者进一步清洗。

数据清洗是数据分析、数据挖掘中一项基本且非常重要的技能,通过在整个数据分析中所用时间的比例会比较高。

当然,本次数据清洗的过程,还有可以优化的地方,各位同学可以自行研究下。

公众号后台回复"2017038",获取本文的源代码及原始数据文件。

如果您喜欢我的文章,欢迎转发(据说转发的同学更有气质哦),哈~~

推荐阅读:


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

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