数据治理 | 工企地址清洗——Python的妙用
本文目录
前言
一、案例背景
二、数据清洗流程
理解数据,明确需求
制定处理计划
按计划处理数据
(1)处理【地址信息表】
(2)处理【企业规模表】
(3)合并数据
整理保存代码
三、总结
本文数据激情放送!
2005年部分工业企业规模.xlsx
2005年部分工业企业地址信息表.xlsx
关注我们,公众号对话框内发送关键词“20220602”即可获取!
本文共4598个字,阅读大约需要12分钟,欢迎指正!
Part1前言
过去的几个月时间里,我们已经为公众号的读者们奉献了二十多篇技术文章,内容包括数据库的安装和使用、数据采集、数据清洗等等。上一阶段的文章中,我们着重为大家介绍了 Python 中最重要的数据处理与数据分析模块——Pandas,详细介绍了其中十余个数据处理技巧,为大家的数据清洗“事业”尽了绵薄之力。
理论是军官,实践是士兵。介绍完这些数据清洗技能,是时候将学到的技能投入到实战当中了,接下来我们将会使用真实社科数据给大家介绍几个完整的数据清洗案例,并以由易到难的顺序呈现给大家。希望各位读者朋友能够投入其中,找到数据清洗与处理的 “感觉”。
Part2案例背景
小李收到上级的数据处理需求,需要清洗两份数据,并将他们合并为一张表。
原始数据如下:
表1 2005年部分工业企业地址信息表 (下称“地址信息表”)
表2 2005年部分工业企业规模表(下称“企业规模表”)
具体需求如下:
根据【地址信息表】获取这些企业的地址(将省份、地市、区县和村等信息拼接在一起)以及企业所在地的六位行政区划代码(县级行政区划代码)。 将【企业规模表】中的企业规模代码,轻重工业代码分别替换为文字。其中企业规模中的1,2,3 分别表示小,中,大型企业;轻重工业中的 1,2 分别表示轻工业企业和重工业企业。 将两张表合并为一张表,删除不需要的字段。
Part3数据清洗流程
1理解数据,明确需求
理解数据必然是处理数据的前提,了解不同数据的含义,可以帮助我们分析处理数据,避免数据处理过程中出现一些低级错误。同时,理解数据也不仅仅是理解数据的含义,还要了解数据的结构和特征,比如数据是否存在缺失、那些地方缺失,为什么会缺失?同样地,异常数据和重复数据的情况也应该在理解数据的范畴之内。
小李在观察数据【地址信息表】时发现以下问题:
“地市”,“乡镇”,“村/门牌号”三个字段存在缺失值; “区县”,“乡镇”,“村/门牌号”三个字段存在一些异常数据; 由于一些地市下面没有县级的行政区划,于是出现“地市”和“区县”两字段内容一样。
如下图所示:
数据【企业规模表】则没有什么问题。
明确需求自然不必多说,从哪里来,要往何处去,就是接下来我们要做的事情。
本文数据激情放送!
2005年部分工业企业规模.xlsx
2005年部分工业企业地址信息表.xlsx
关注我们,公众号对话框内发送关键词“20220602”即可获取!
2制定处理计划
在明确需求的基础上,我们可以为整个处理数据的过程合理地划分为几个步骤。化繁为简,逐一解决,这样做不仅能够帮助我们明确处理思路,还有利于保存和阅读处理数据的代码。更重要的是,养成这样的习惯,做很多事情都会十分轻松。
对于本文的数据需求来说,制定一个计划非常简单:
按需求处理【地址信息表】,删除不需要的字段 按需求处理【企业规模表】,删除不需要的字段 根据“企业ID”字段将处理后的【地址信息表】和【企业规模】匹配为一张表
3按计划处理数据
处理【地址信息表】
地址信息表主要有两个部分需要处理。第一,原始数据给出了12位行政区划代码,而我们只需要六位行政区划,即 12 位行政区划代码的前 6 位。第二,将省份,地市等地址信息按顺序拼接在一起即可得到一个较为详细的地址。
首先,我们需要使用使用 Pandas 读取数据,读取数据时需要注意,我们可以根据后续需要做的处理,给读取数据的方法添加合适的参数。比如,我们需要获取 12 行政区划代码的前 6 位,所以需要将“行政区划代码”这一字段读取为字符型,以便后面分割数据使用。
值得一提的是,Excel 表(文件扩展名为".xlsx" 或 ".xls")可以将数字保存为不同类型,比如,Excel 表可以将数字 100 保存为整数 100,也可以将其保存为字符 "100",这样一来,使用其他工具读取 Excel 时可以识别出数字是何种类型。但是 csv 文件不能将数字保存为指定类型,csv 文件本质上是使用特定符号分隔开的文本文件,所以读取 csv 文件时需要注意数字数据的类型。
读取数据【地址信息表】的 Python 代码如下:
import pandas as pd
# 使用 dtype 参数将“行政区划代码”读取为字符型
data_DZ = pd.read_excel('2005年部分工业企业地址信息表.xlsx',\
dtype={'行政区划代码':str})
# 输出数据的行数
print(data_DZ.shape[0) # 输出:10000
data_DZ.head()
读取数据后可以使用 info()
方法快速查看数据缺失情况。
data_DZ.info()
根据上图中红色方框中的信息可以查看到八个字段中,有三列数据存在缺失值。例如,乡镇 67803 non-null 代表“乡镇”这一列有 67803 个非空数据,而数据总行数是 10000,也就是说,这一列存在 32197 个缺失值。
回归正题,读取数据后,我们先将 12 位行政区划代码替换为 6 位行政区划代码,代码如下:
# 使用 apply 方法,获取 12 位行政区划代码的前 6 位
data_DZ['行政区划代码'] = data_DZ['行政区划代码'].apply(lambda x: x[:6])
data_DZ.head()
接下来需要将省份,地市等字段拼接在一起接可以得到完整的地址了,但是拼接之前需要先清洗数据。前面讲到,小李在观察数据时发现【地址信息表】存在三个问题,接下来我们按顺序处理这些问题,首先处理缺失数据,我们已经知道,Pandas 中的缺失值主要是 NaN,这是一种 float 型数据,无法参与字符拼接;同时为了缺失值不影响拼接后的地址,我们可以将缺失值填充为空字符,代码如下:
# 将空值填充为空字符 ''
data_DZ = data_DZ.fillna('')
下面处理异常地址,国内的区县,乡镇都是使用中文命名的,所以我们可以将不含中文的数据当作异常值,并将这些异常值替换为空字符。那么如何判断一个字符串是否含有中文呢?我们有正则表达式!处理方法和代码如下:
# 导入正则表达式模块
import re
# 自定义一个方法,用于将不含中文的数据替换为空
def contain_cn(S):
'''
若字符串 S 中含中文,则返回 S,
否则返回空字符
'''
# 正则表达式 '[\u4e00-\u9fa5]' 用于识别中文汉字
if bool(re.search('[\u4e00-\u9fa5]', S)) == True:
# 若字符含有任意中文汉字,则不做处理,返回输入的数据
return S
else:
# 若字符不含含任一中文汉字,则返回空字符 ''
return ''
# 将上面这个方法应用到“区县”,“乡镇”,“村/门牌号”三个字段
data_DZ['区县'] = data_DZ['区县'].apply(contain_cn)
data_DZ['乡镇'] = data_DZ['乡镇'].apply(contain_cn)
data_DZ['村/门牌号'] = data_DZ['村/门牌号'].apply(contain_cn)
# 根据"企业ID"查看异常数据是否被处理
data_DZ[data_DZ['企业ID'] == 82403]
之前的异常数据应经被替换为空字符。
随后再处理第三个问题,我们可以先将“地市”和“区县”两个字段合并为一个字段“地市和区县”,如果两者不同,则拼接在一起;如果相同,则返回其中一个即可。处理代码如下:
def merge_city_county(df):
'''合理得合并地市和区县'''
city = df['地市']
county = df['区县']
if city != county:
# 若地市和区县不相同,返回拼接的结果
return city + county
else:
# 若地市和区县相同,返回其中一个
return city
# 合并“地市”和“区县”,得到新字段“地市和区县”
data_DZ['地市和区县'] = data_DZ[['地市', '区县']].apply(merge_city_county,axis=1)
data_DZ.head()
最后,将“省份”,“地市和区县”,“乡镇”,“村/门牌号” 四个字段拼接在一起就得到了一个合理的地址。合并后将多余字段删除就处理完【地址信息表】了,拼接字段和删除字段的代码如下:
# \ 是换行符,一行代码过长时可以使用
data_DZ['企业地址'] = data_DZ['省份']\
+ data_DZ['地市和区县']\
+ data_DZ['乡镇']\
+ data_DZ['村/门牌号']
# axis=1 代表删除的是数据列,inplace=True 代表这个操作在原数据上生效
data_DZ.drop(['省份', '地市', '区县', '乡镇', '村/门牌号', '地市和区县'],\
axis=1,\
inplace=True)
data_DZ.head()
处理【企业规模表】
相比于处理【地址信息表】,处理【企业规模表】要容易很多,只需要将企业规模代码和轻重工业代码替换为相应的文字即可。
首先读取数据,代码如下:
# 使用 dtype 参数将“区号”和“固定电话”两字段读取为字符型
data_GM = pd.read_excel('2005年部分工业企业规模.xlsx')
data_GM.head()
可以使用 map()
方法来批量替换数据值,替换之前需要构建替换字典,代码如下:
# 构建替换字典
dict_GM = {'1':'小型企业', '2':'中型企业', '3':'大型企业'}
dict_QZ = {'1':'轻工业企业', '2':'重工业企业'}
# 替换数据
data_GM['企业规模'] = data_GM['企业规模'].map(dict_GM)
data_GM['轻重工业'] = data_GM['轻重工业'].map(dict_QZ)
data_GM.head()
合并数据
以上两份数据描述的是同样的企业,但是他们的企业ID并不是按照顺序排列的,所以不能机械地将他们合并在一起,而是需要使用“企业ID”或“企业名称”字段将两表匹配到一起。数据匹配的代码如下:
# 同时使用'企业ID'和'企业名称'两个字段进行匹配,避免生成重复的字段
DATA_merge = pd.merge(left=data_DZ,\
right=data_GM,\
on=['企业ID','企业名称'],\
how='inner')
DATA_merge
到此为止,小李的数据处理工作已经全部完成,只需要将最终的数据保存为 Excel 表或者 csv 文件即可。如果数据量很大,建议保存为 csv 文件(Excel 至多可以保存 1048576 行的数据表);如果数据量较小且需要使用工具打开查看,修改,则建议保存为 Excel 表。保存数据的代码如下:
# 保存为 Excel 表
# index=False 表示不将 DataFrame 索引写入数据
DATA_merge.to_excel('合并表.xlsx', index=False)
# 保存为 csv 文件
# encoding 表示写入文件的编码格式,指定为 'utf-8-sig' 可以最大程度地避免出现乱码
DATA_merge.to_excel('合并表.xlsx', index=False, encoding='utf-8-sig')
4整理保存代码
保存代码是一个好习惯,万一以后用得着呢?保存代码的方式有很多种,主要有以下几种方式:
将代码源文件保存到硬盘 将代码上传至一些云平台 将代码整理为文档并保存
Part4总结
一个看似简单的数据需求,里面往往藏着很多细节。在数据清洗过程中,我们的大部分精力可能会用在处理缺失值,重复值和异常值上面。而这部分则很考验操作者的细心程度,所以我们在数据清洗、处理的过程中,一定要十分仔细。
本文数据激情放送!
2005年部分工业企业规模.xlsx
2005年部分工业企业地址信息表.xlsx
关注我们,公众号对话框内发送关键词“20220602”即可获取!
我们将在数据治理板块中推出一系列原创推文,帮助读者搭建一个完整的社科研究数据治理软硬件体系。该板块将涉及以下几个模块(点击标题即可跳转至相应合集):
星标⭐我们不迷路!想要文章及时到,文末“在看”少不了!
点击搜索你感兴趣的内容吧
往期推荐
数据Seminar
这里是大数据、分析技术与学术研究的三叉路口
文 | 《社科领域大数据治理实务手册》
欢迎扫描👇二维码添加关注