python-数据分析-Pandas-2、DataFrame对象-数据获取
如果使用 pandas 做数据分析,那么DataFrame一定是被使用得最多的类型,它可以用来保存和处理异质的二维数据。
这里所谓的“异质”是指DataFrame中每个列的数据类型不需要相同,这也是它区别于 NumPy 二维数组的地方。
DataFrame提供了极为丰富的属性和方法,帮助我们实现对数据的重塑、清洗、预处理、透视、呈现等一系列操作。
# -*- coding: utf-8 -*-
#DataFrame
import numpy
import pandas
# 1、通过二维数组创建DataFrame对象
scores = numpy.random.randint(60, 101, (5, 3)) # 生成60到100的数组--5行3列
courses = ['语文', '数学', '英语'] # 生成语文、数学、英语的数组
stu_ids = numpy.arange(1001, 1006) # 生成1001到1005的数组
# 创建DataFrame对象
# data:二维数组,columns:列名,index:行名
df1 = pandas.DataFrame(data=scores, columns=courses, index=stu_ids)
print(df1)
'''
语文 数学 英语
1001 67 61 82
1002 71 93 81
1003 73 65 74
1004 75 80 71
1005 81 95 71
'''
print('-------------------------------------------')
#通过字典创建DataFrame对象
scores = {
'语文': [62, 63, 64, 65, 66],
'数学': [67, 68, 69, 70, 71],
'英语': [72, 73, 74, 75, 76]
}
stu_ids = numpy.arange(1001, 1006)
df2 = pandas.DataFrame(data=scores, index=stu_ids)
print(df2)
'''
语文 数学 英语
1001 62 67 72
1002 63 68 73
1003 64 69 74
1004 65 70 75
1005 66 71 76
'''
print('-------------------------------------------')
通过读取CSV文件创建DataFrame对象
#读取csv文件创建DataFrame对象
#可以通过pandas模块的read_csv函数来读取csv文件、read_csv函数的参数非常多、如下:
"""
sep / delimiter:分隔符,默认是 , 逗号
header:表头(列索引)的位置,默认值是infer,用第一行的内容作为表头(列索引)。
index_col:用作行索引(标签)的列。
usecols:需要加载的列,可以使用序号或者列名。
true_values / false_values:哪些值被视为布尔值True / False。
skiprows:通过行号、索引或函数指定需要跳过的行。
skipfooter:要跳过的末尾行数。
nrows:需要读取的行数。
na_values:哪些值被视为空值。
iterator:设置为True,函数返回迭代器对象。
chunksize:配合上面的参数,设置每次迭代获取的数据体量。
"""
df3 = pandas.read_csv('file/2023年北京积分落户数据.csv', index_col='公示编号')
print(df3)
'''
姓名 出生年月 单位名称 积分分值
公示编号
202300001 张浩 1977-02 北京首钢股份有限公司 140.05
202300002 冯云 1982-02 中国人民解放军空军二十三厂 134.29
202300003 王天东 1975-01 中建二局第三建筑工程有限公司 133.63
202300004 陈军 1976-07 中建二局第三建筑工程有限公司 133.29
202300005 樊海瑞 1981-06 中国民生银行股份有限公司 132.46
... ... ... ... ...
202305999 曹恰 1983-09 首都师范大学科德学院 109.92
202306000 罗佳 1981-05 厦门方胜众合企业服务有限公司海淀分公司 109.92
202306001 席盛代 1983-06 中国华能集团清洁能源技术研究院有限公司 109.92
202306002 彭芸芸 1981-09 北京汉杰凯德文化传播有限公司 109.92
202306003 张越 1982-01 大爱城投资控股有限公司 109.92
[6003 rows x 4 columns]
'''
读取Excel表格创建DataFrame对象
#读取Excel表格创建DataFrame对象""
#sheet_name:指定读取的sheet页,默认读取第一个sheet页。
df4 = pandas.read_excel('file/2022年股票数据.xlsx', sheet_name='AMZN', index_col='Date')
print(df4)
'''
Open High Low Close Volume
Date
2022-12-30 83.120 84.050 82.4700 84.000 62401194
2022-12-29 82.870 84.550 82.5500 84.180 54995895
2022-12-28 82.800 83.480 81.6900 81.820 58228575
2022-12-27 84.970 85.350 83.0000 83.040 57284035
2022-12-23 83.250 85.780 82.9344 85.250 57433655
... ... ... ... ... ...
2022-01-07 163.839 165.243 162.0310 162.554 46605900
2022-01-06 163.450 164.800 161.9370 163.254 51957780
2022-01-05 166.883 167.126 164.3570 164.357 64302720
2022-01-04 170.438 171.400 166.3490 167.522 70725160
2022-01-03 167.550 170.704 166.1600 170.404 63869140
[251 rows x 5 columns]
'''
通过读取关系型数据库二维表创建DataFrame对象
pandas
模块的read_sql
函数可以通过 SQL 语句从数据库中读取数据创建DataFrame
对象,该函数的第二个参数代表了需要连接的数据库。
对于 MySQL 数据库,我们可以通过pymysql
或mysqlclient
来创建数据库连接(需要提前安装好三方库),得到一个Connection
对象,而这个对象就是read_sql
函数需要的第二个参数
# -*- coding: utf-8 -*-
#读取关系数据库二维表创建DataFrame对象
import pandas
import pymysql
from sqlalchemy import create_engine
# #方法一:
# #创建一个mysql数据库的连接对象""
# conn = pymysql.connect(
# host='172.16.8.184',
# user='root',
# password='123456',
# port=3307,
# database='iamdb',
# charset='utf8'
# )
# #通过sql从数据库二维表读取数据创建DataFrame
# df5 = pandas.read_sql('select * from sys_user', conn, index_col='id')
# print(df5)
#执行上面的代码会出现一个警告,因为 pandas 库希望我们使用SQLAlchemy三方库接入数据库,
# 具体内容是:“UserWarning: pandas only supports SQLAlchemy connectable (engine/connection) or database string URI or sqlite3 DBAPI2 connection. Other DBAPI2 objects are not tested. Please consider using SQLAlchemy.”。
# 如果不想看到这个警告,我们可以试一试下面的解决方案。
#方法二:(推荐)
#使用SQLAlchemy引擎连接数据库:替换原来的pymysql.connect为create_engine函数创建的引擎。
# URL字符串包含了数据库类型(mysql+pymysql)、用户名、密码、主机地址、端口和数据库名,以及字符集设置
## 创建SQLAlchemy引擎连接MySQL数据
#使用read_sql_query而非read_sql:虽然在这个上下文中两者通常可以互换使用,但明确使用read_sql_query可以更好地表达意图,即执行SQL查询来读取数据
engine = create_engine("mysql+pymysql://root:123456@172.16.8.184:3307/iamdb?charset=utf8")
df6 = pandas.read_sql_query('select * from sys_user', engine, index_col='id')
print(df6)
'''
created_at updated_at ... locked_at regions
id ...
1 2023-08-10 10:35:48 2024-02-28 14:25:08 ... None None
2 2023-08-10 10:43:00 2024-06-05 16:29:17 ... None
3 2023-08-10 10:43:53 2023-10-27 11:11:34 ... None None
4 2023-08-10 10:45:12 2023-10-20 09:46:40 ... None None
5 2023-08-11 10:38:54 2023-08-11 10:38:54 ... None None
.. ... ... ... ... ...
60 2024-03-26 16:07:03 2024-03-26 16:07:54 ... None None
61 2024-04-03 14:10:57 2024-05-08 11:53:50 ... None 深圳地区
62 2024-05-14 15:43:37 2024-05-17 14:54:39 ... None 广州地区
63 2024-05-21 18:49:18 2024-05-28 10:03:05 ... None
64 2024-05-22 17:12:16 2024-05-22 17:12:33 ... None
[61 rows x 15 columns]
'''
#我们再来加载特定字段的数据创建DataFrame对象。
df7 = pandas.read_sql_query('select id,username,password,nickname from sys_user', engine, index_col='id')
print(df7)
engine.connect().close() #关闭连接、释放资源
##说明:如果通过表名加载二维表数据,也可以将上面的函数换成read_sql_table。
df8 = pandas.read_sql_table('sys_user', engine, index_col='id')
print(df8) #获取整个表的数据
DataFrame 的基本属性和方法
属性名 | 说明 |
---|---|
at / iat |
通过标签获取DataFrame 中的单个值。 |
columns |
DataFrame 对象列的索引 |
dtypes |
DataFrame 对象每一列的数据类型 |
empty |
DataFrame 对象是否为空 |
loc / iloc |
通过标签获取DataFrame 中的一组值。 |
ndim |
DataFrame 对象的维度 |
shape |
DataFrame 对象的形状(行数和列数) |
size |
DataFrame 对象中元素的个数 |
values |
DataFrame 对象的数据对应的二维数组 |
先建三个表
#1、部门表 dept_df
CREATE TABLE `dept_df` (
`dno` int unsigned NOT NULL AUTO_INCREMENT,
`dname` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`dloc` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
PRIMARY KEY (`dno`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=41 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC
# 2、员工表(emp_df)
CREATE TABLE `emp_df` (
`eno` int unsigned NOT NULL AUTO_INCREMENT,
`ename` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`job` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`mgr` float CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`sal` int CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`comm` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`dno` int CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
PRIMARY KEY (`eno`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=7801 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC
# 3、员工表2(emp2_df)
CREATE TABLE `emp2_df` (
`eno` int unsigned NOT NULL AUTO_INCREMENT,
`ename` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`job` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`mgr` float CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`sal` int CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`comm` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`dno` int CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
PRIMARY KEY (`eno`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=9901 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC
========================================================
#对应的csv数据
#1、部门表 dept_df
dno,dname,dloc
10,会计部,北京
20,研发部,成都
30,销售部,重庆
40,运维部,深圳
# 2、员工表(emp_df)
eno,ename,job,mgr,sal,comm,dno
1359,胡一刀,销售员,3344.0,1800,200.0,30
2056,乔峰,分析师,7800.0,5000,1500.0,20
3088,李莫愁,设计师,2056.0,3500,800.0,20
3211,张无忌,程序员,2056.0,3200,NaN,20
3233,丘处机,程序员,2056.0,3400,NaN,20
3244,欧阳锋,程序员,3088.0,3200,NaN,20
3251,张翠山,程序员,2056.0,4000,NaN,20
3344,黄蓉,销售主管,7800.0,3000,800.0,30
3577,杨过,会计,5566.0,2200,NaN,10
3588,朱九真,会计,5566.0,2500,NaN,10
4466,苗人凤,销售员,3344.0,2500,NaN,30
5234,郭靖,出纳,5566.0,2000,NaN,10
5566,宋远桥,会计师,7800.0,4000,1000.0,10
7800,张三丰,总裁,NaN,9000,1200.0,20
#3、员工表2(emp2_df)
eno,ename,job,mgr,sal,comm,dno
9500,张三丰,总裁,NaN,50000,8000,20
9600,王大锤,程序员,9800.0,8000,600,20
9700,张三丰,总裁,NaN,60000,6000,20
9800,骆昊,架构师,7800.0,30000,5000,20
9900,陈小刀,分析师,9800.0,10000,1200,20
# -*- coding: utf-8 -*-
#DataFrame属性和方法
#在开始讲解DataFrame的属性和方法前,我们先从之前提到的hrs数据库中读取三张表的数据,创建出三个DataFrame对象,完整的代码如下所示
import pandas
from sqlalchemy import create_engine
#创建连接
engine = create_engine('mysql+pymysql://root:123456@192.168.177.190:3307/demo?charset=utf8')
dept_df = pandas.read_sql_table('dept_df', con=engine, index_col='dno')
emp_df = pandas.read_sql_table('emp_df', con=engine, index_col='eno')
emp2_df = pandas.read_sql_table('emp2_df', con=engine, index_col='eno')
print(dept_df)
print(emp_df)
print(emp2_df)
#得到的三个DataFrame对象如下所示。
'''
#部门表(dept_df),其中dno是部门的编号,dname和dloc分别是部门的名称和所在地。
dname dloc
dno
10 会计部 北京
20 研发部 成都
30 销售部 重庆
40 运维部 深圳
#员工表(emp_df),其中eno是员工编号,ename、job、mgr、sal、comm和dno分别代表员工的姓名、职位、主管编号、月薪、补贴和部门编号。
ename job mgr sal comm dno
eno
1359 胡一刀 销售员 3344.0 1800 200.0 30
2056 乔峰 分析师 7800.0 5000 1500.0 20
3088 李莫愁 设计师 2056.0 3500 800.0 20
3211 张无忌 程序员 2056.0 3200 NaN 20
3233 丘处机 程序员 2056.0 3400 NaN 20
3244 欧阳锋 程序员 3088.0 3200 NaN 20
3251 张翠山 程序员 2056.0 4000 NaN 20
3344 黄蓉 销售主管 7800.0 3000 800.0 30
3577 杨过 会计 5566.0 2200 NaN 10
3588 朱九真 会计 5566.0 2500 NaN 10
4466 苗人凤 销售员 3344.0 2500 NaN 30
5234 郭靖 出纳 5566.0 2000 NaN 10
5566 宋远桥 会计师 7800.0 4000 1000.0 10
7800 张三丰 总裁 NaN 9000 1200.0 20
#员工表(emp2_df),跟上面的员工表结构相同,但是保存了不同的员工数据。
ename job mgr sal comm dno
eno
9500 张三丰 总裁 NaN 50000 8000 20
9600 王大锤 程序员 9800.0 8000 600 20
9700 张三丰 总裁 NaN 60000 6000 20
9800 骆昊 架构师 7800.0 30000 5000 20
9900 陈小刀 分析师 9800.0 10000 1200 20
'''
# 1、info() 方法
# info() 方法用于显示DataFrame对象的基本信息,包括行数、列数、列名、列类型、非空行数等。
print(emp_df.info())
'''
<class 'pandas.core.frame.DataFrame'>
Index: 14 entries, 1359 to 7800
Data columns (total 6 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 ename 14 non-null object
1 job 14 non-null object
2 mgr 14 non-null object
3 sal 14 non-null object
4 comm 14 non-null object
5 dno 14 non-null object
dtypes: object(6)
memory usage: 784.0+ bytes
None
'''
print('--------------------------------------------')
# 2、head() 查看DataFrame头部的数据、默认查看前5行的数据
print(emp_df.head())
# 3、tail() 查看DataFrame尾部的数据、默认查看后5行的数据
print(emp_df.tail())
print('--------------------------------------------')
# 4、操作数据
#索引和切片
#获取DataFrame的某一列、如取出emp_df的ename列:两种方法
print(emp_df['ename'])
print(emp_df.ename)
#执行上面的代码可以发现,我们获得的是一个Series对象(包含数据和索引-索引可自定义也可默认)、获得的是eno列和ename 两列的数据。
print('--------------------------------------------')
# 5、获取DataFrame的某一行
#可以使用整数索引或我们设置的索引,例如取出员工编号为2056的员工数据
# loc[2056]表示获取员工编号为2056的员工数据
print(emp_df.loc[2056])
# iloc[1]表示获取第2行数据,iloc[0]表示获取第1行数据,iloc[1:3]表示获取第2行到第3行数据,iloc[1:3, 1:3]表示获取第2行到第3行,第2列到第3列的数据。
#print(emp_df.iloc[1])
#通过执行上面的代码我们发现,单独取DataFrame 的某一行或某一列得到的都是Series对象
print('--------------------------------------------')
# 6、通过花式索引来获取多个行或多个列的数据,花式索引的结果仍然是一个DataFrame对象
#获取多个列:
print(emp_df[['ename', 'job']])
#获取多个行:
print(emp_df.loc[[2056, 7800, 3344]])
print('--------------------------------------------')
# 7、获取或修改DataFrame 对象某个单元格的数据,需要同时指定行和列的索引,例如要获取员工编号为2056的员工的职位信息,
print(emp_df['job'][2056]) #分析师
print(emp_df.loc[2056, 'job']) #推荐使用这种、因为它只做了一次索引运算 分析师
print(emp_df.loc[2056]['job']) #分析师
#将该员工的职位修改为“架构师”
emp_df.loc[2056, 'job'] = '架构师'
print(emp_df.loc[2056, 'job'])
print('--------------------------------------------')
#数据筛选
#通过布尔索引对DataFrame对象进行数据筛选,例如我们要从emp_df中筛选出月薪超过3500的员工
filtered_emp_df = emp_df[emp_df['sal'] > 3500]
print(filtered_emp_df)
'''
ename job mgr sal comm dno
eno
2056 乔峰 架构师 7800.0 5000 1500.0 20
3251 张翠山 程序员 2056.0 4000 NaN 20
5566 宋远桥 会计师 7800.0 4000 1000.0 10
7800 张三丰 总裁 NaN 9000 1200.0 20
'''
print('--------------------------------------------')
#从emp_df中筛选出月薪超过3500且部门编号为20的员工
filtered_emp_df = emp_df[(emp_df.sal > 3500) & (emp_df['dno'] == 20)]
print(filtered_emp_df)
# print(emp_df[(emp_df.sal > 3500) & (emp_df.dno == 20)])
'''
ename job mgr sal comm dno
eno
2056 乔峰 架构师 7800.0 5000 1500.0 20
3251 张翠山 程序员 2056.0 4000 NaN 20
7800 张三丰 总裁 NaN 9000 1200.0 20
'''
print('--------------------------------------------')
#除了使用布尔索引,DataFrame对象的query方法也可以实现数据筛选,query方法的参数是一个字符串,它代表了筛选数据使用的表达式,而且更符合 Python 程序员的使用习惯
filtered_emp_df = emp_df.query('sal > 3500 and dno == 20')
print(filtered_emp_df)
'''
ename job mgr sal comm dno
eno
2056 乔峰 架构师 7800.0 5000 1500.0 20
3251 张翠山 程序员 2056.0 4000 NaN 20
7800 张三丰 总裁 NaN 9000 1200.0 20
'''
iloc 与 loc 的区别
.loc 和 .iloc 的作用
.loc
.loc 是基于标签(标签索引)的选取方式,可以使用行标签和列标签来选取数据。
作用:通过行和列的标签(名字)来访问数据。
语法:emp_df.loc[row_label, column_label]
row_label:行标签,可以是单个标签或列表、切片。
column_label:列标签,可以是单个标签或列表、切片。
.iloc
.iloc 是基于整数位置(位置索引)的选取方式,使用行和列的位置索引来选取数据。
作用:通过行和列的整数位置来访问数据。
语法:emp_df.iloc[row_index, column_index]
row_index:行位置,可以是单个整数或列表、切片。
column_index:列位置,可以是单个整数或列表、切片。