第5 章 Pandas 数据获取与清洗 对于数据分析而言,数据大部分来源于外部数据,如常用的CSV 文件、Excel文件和数 据库文件等。Pandas库将外部数据转换为DataFrame数据格式,处理完成后再存储到相应 的外部文件中。 前期采集到的数据,或多或少都存在一些瑕疵和不足,如数据缺失、极端值、数据格式不 统一等问题。数据预处理不仅可以提高初始数据的质量,保留与分析目标联系紧密的数据, 而且可以优化数据的表现形式,有助于提高数据分析或数据挖掘工作的效率和准确率。 数据清洗主要是将“脏”数据变成“干净”数据的过程,该过程中会通过一系列的方法对 “脏”数据进行处理,以达到清除冗余数据、规范数据、纠正错误数据的目的。 接下来,本节将针对Pandas中数据获取、清洗与格式化处理的内容进行详细讲解。 5.1 数据获取操作 在对数据进行分析时,通常不会将需要分析的数据直接写入程序中,这样不仅造成程序 代码臃肿,而且可用率很低。常用的方法是将需要分析的数据存储到本地,之后再对存储文 件进行读取。 初始数据获取是预处理的第一步,该步骤主要负责从文件、数据库、网页等众多渠道中 获取数据,以得到预处理的初始数据,为后续的处理工作做好数据准备。 针对不同的存储文件,Pandas读取数据的方式是不同的。Pandas将数据加载到 DataFrame后,就可以使用DataFrame对象的属性和方法进行操作。这些操作有的是完成 数据分析中的常规统计工作,有的是对数据的加工处理。 接下来,本节将针对常用存储格式文件的读写进行介绍。 5.1.1 读取文本(CSV 和TXT)文件 文本文件是一种由若干行字符构成的计算机文件,它是一种典型的顺序文件。CSV (Comma-SeparatedValues)是一种逗号分隔的文件格式,因为其分隔符不一定是逗号,又被 称为字符分隔文件,文件以纯文本形式存储表格数据(数字和文本)。CSV 不仅可以是一个 实体文件,还可以是字符形式(如URL+data.csv),以便于在网络上传输。 CSV 文件是一种纯文本文件,可以使用任何文本编辑器进行编辑,它支持追加模式,节 省内存开销。因为CSV 文件具有诸多的优点,所以在很多时候会将数据保存到CSV 文 件中。 CSV 不带数据样式,标准化较强,是最为常见的数据格式。 1 24 Python 大数据分析与可视化 Pandas中提供了read_csv()函数用于读取CSV 文件,关于它们的具体介绍如下。 1.通过read_csv()函数读取CSV 文件的数据 read_csv()函数的作用是将CSV 文件的数据读取出来,并转换成DataFrame对象。 read_csv()函数的语法格式如下。 read_csv(filepath_or_buffer,sep= ',', delimiter= None, header= 'infer', names= None, index_col=None, usecols=None, prefix=None,nrows=None, …) 参数说明如下。 .filepath_or_buffer:表示文件路径,可以为URL字符串。没有默认值,也不能为空, 根据Python的语法,第一个参数传参时可以不写参数名。 .sep:接收string,代表每行数据内容的分隔符。read_csv默认为“,”,read_table默 认为制表符“[Tab]”,如果分隔符指定错误,在读取数据的时候,每一行数据将连成 一片。read_csv()函数还提供了一个参数名为delimiter的定界符,这是一个备选分 隔符,是sep的别名,效果和sep一样。如果指定该参数,则sep参数失效。常见参 数的有以下形式。 pd.read_csv(r'./data.csv',sep='\t') #指定制表符分隔Tab pd.read_csv(r'./data.csv',sep='(? 标签表格数据解析 为DataFrame。如返回有多个df的列表,则可以通过索引指定取第几个。如果页面里只有 一个表格,那么这个列表就只有一个DataFrame。 read_html()函数的语法格式如下。 pandas.read_html(io, match='.+', flavor=None, header=None, index_col=None,skiprows=None, encoding=None,attrs=None) 参数说明如下。 .io:字符串,文件路径,也可以是URL链接。如果网址不接受https,可以尝试去掉 https中的s后爬取。 1 30 Python 大数据分析与可视化 . match:正则表达式,返回与正则表达式匹配的表格。 .flavor:解析器默认为“lxml”。 . header:指定列标题所在的行,列表list为多重索引。 .index_col:指定行标题对应的列,列表list为多重索引。 .encoding:字符串,默认为None,文件的编码格式。 .attrs:默认为None,用于表示表格的属性值。 在使用read_html()函数时,首先要确定网页表格是否为标签。可以通过在 网页中单击右键,在弹出的菜单中选择“查看源文件”,查看代码是否含有表格标签“
”的字样,然后才使用read_html()函数。 【例5-7】 读取新浪网上的大学部分专业信息。 import pandas as pd import requests html_ data = requests. get ( ' http://kaoshi. edu. sina. com. cn/college/majorlist? page=1') html_table_data = pd.read_html(html_data.content,header=0,encoding='utf-8') columns = ['专业名称','专业代码','专业大类','专业小类'] df = pd.DataFrame(data=html_table_data[1],columns=columns) print(df.head()) 运行结果: 专业名称专业代码专业大类专业小类 0 哲学类101 哲学哲学类 1 哲学10101 哲学哲学类 2 逻辑学10102 哲学哲学类 3 宗教学10103 哲学哲学类 4 伦理学10104 哲学哲学类 值得一提的是,在使用read_html()函数读取网页中的表格数据时,需要注意网页的编 码格式。运行程序,如果出现“ImportError:lxmlnotfound,pleaseinstallit”的错误提示信 息,则需要安装lxml模块。 5.1.5 读取MySQL 数据库中数据 大多数情况下,海量的数据是使用数据库进行存储的,这主要是依赖于数据库的数据结 构化、数据共享性、独立性等特点。因此,在实际生产环境中,绝大多数的数据都是存储在数 据库中。 Pandas支持MySQL、Oracle、SQLite等主流数据库的读写操作。 为了高效地对数据库中的数据进行读取,这里需要引入SQLAlchemy。SQLAlchemy 是使用Python编写的一款开源软件,它提供的SQL工具包和对象映射工具能够高效地访 问数据库。在使用SQLAlchemy时需要使用相应的连接工具包,如MySQL 需要安装 mysqlconnector,Oracle则需要安装cx_oracle。 Pandas的io.sql模块中提供了常用的读写数据库函数,read_sql_table()函数与read_ sql_query()函数都可以将读取的数据转换为DataFrame对象,前者表示将整张表的数据转 换成DataFrame,后者则表示将执行SQL语句的结果转换为DataFrame对象。而read_sql() 第5 章 Pandas 数据获取与清洗1 31 函数同时支持read_sql_table()函数与read_sql_query()函数两者的功能。to_sql()方法则 是把记录数据写到数据库里。 在连接MySQL数据库时,这里使用的是mysqlconnector驱动,如果当前的Python环 境中没有该模块,则需要使用pipinstallmysql-connector命令安装该模块。下面以read_ sql()函数和to_sql()方法为例,分别介绍如何读写数据库中的数据,具体内容如下。 1.使用read_sql()函数读取数据 read_sql()函数既可以读取整张数据表,又可以执行SQL语句,其语法格式如下。 pandas.read_sql(sql,con,index_col= None,coerce_float= True,params= None,parse_ dates=None, columns=None, chunksize=None) 参数说明如下。 .sql:表示被执行的SQL语句。 .con:接收数据库连接,表示数据库的连接信息。 .index_col:默认为None,如果传入一个列表,则表示为层次化索引。 .coerce_float:将非字符串、非数字对象的值转换为浮点数类型。 . params:传递给执行方法的参数列表,如params={'name':'value'}。 .columns:接收list表示读取数据的列名,默认为None。 如果发现数据中存在空值,则会使用NaN 进行补全。 【例5-8】 使用read_sql()函数读取数据库中的数据表specialty。 import pandas as pd from sqlalchemy import create_engine #mysql 账号为root,密码为123456,数据名为jxgl #数据表名称:specialty engine = create_engine('mysql+pymysql://' 'root:123456@127.0.0.1:3306/jxgl') #通过数据表名读取数据库的数据 #category_data = pd.read_sql('specialty', engine) #也可以通过SQL 语句读取数据库的数据 sql = 'SELECT * FROM specialty' df_data = pd.read_sql(sql, engine) print(df_data) 运行结果: zno zname 0 1102 数据科学与大数据技术 1 1103 人工智能 2 1201 网络与新媒体 3 1214 区块链科学与工程 4 1407 健康服务与管理 5 1409 智能医学工程 6 1601 供应链管理 7 1805 智能感知工程 8 1807 智能装备与系统 上述示例中,首先导入了sqlalchemy模块,通过create_engine()函数创建连接数据库 的信息,然后调用read_sql()函数读取数据库中的specialty数据表,并转换成DataFrame 对象。 1 32 Python 大数据分析与可视化 注意:在使用create_engine()函数创建连接时,其格式如下:'数据库类型+数据库驱 动名称://用户名:密码@机器地址:端口号/数据库名'。 需要强调的是,这里的SQL语句不仅是用于筛选的SQL语句,其他用于增删改查的 SQL语句都是可以执行的。 2.使用to_sql()方法将数据写入数据库中 to_sql()方法的功能是将Series或DataFrame对象以数据表的形式写入数据库中,其 语法格式如下。 to_sql(name, con, schema = None, if_exists = 'fail', index = True, index_label = None,chunksize = None,dtype = None) 参数说明如下。 . name:表示数据库表的名称。 .con:表示数据库的连接信息。 .if_exists:可以取值为fail、replace或append,默认为fail。每个取值代表的含义 如下。 fail:如果表存在,则不执行写入操作。 replace:如果表存在,则将源数据库表删除再重新创建。 append:如果表存在,那么在原数据库表的基础上追加数据。 .index:表示是否将DataFrame行索引作为数据传入数据库,默认为True。 .index_label:表示是否引用索引名称。如果index设为True,此参数为None,则使 用默认名称;如果index为层次化索引,则必须使用序列类型。 接下来,通过一个示例程序来演示如何使用Pandas向数据库中写入数据。 首先,创建一个名称为students_info的数据库,具体的SQL语句如下。 CREATE DATABASE students_info CHARASET=utf8 然后,创建一个DataFrame对象,它统计了每个年级中男生和女生的人数。 接着,调用to_sql()方法将DataFrame对象写入名称为students的数据表中,具体代码 如下。 from pandas import DataFrame,Series import pandas as pd from sqlalchemy import create_engine from sqlalchemy.types import * df = DataFrame({"班级":["一年级","二年级","三年级","四年级"], "男生人数":[25,23,27,30], "女生人数":[19,17,20,20]}) #创建数据库引擎 #mysql+pymysql 表示使用MySQL 数据库的pymysql 驱动 #账号:root,密码:123456,数据库名:studnets_info #数据表的名称: students engine=create_engine('mysql+ mysqlconnector://root:123456@127.0.0.1/students_ info') df.to_sql('students',engine) 当程序执行结束后,可以在数据库中查看是否成功创建了数据表,以及数据是否保存成 功,这里使用命令行的方式进行验证。