Pandas 📦
- 表数据处理神器 -- Pandas
Pandas 是 Python 进行数据分析的基础包,基于 NumPy 构建,
该工具是为了解决数据分析任务而创建的。
Pandas 的名称来自于面板数据(
panel data)和python数据分析(data analysis)。
Pandas 纳入了大量库和一些标准的数据模型,提供了高效地操作大型数据集所需的函数和方法,
能使我们快速便捷地处理数据。这也是使 Python 成为强大而高效的数据分析环境的重要因素之一。
一、读取外部数据
在数据科学领域,Python可以完成很多不同的任务,
如数据分析、数据可视化、数据挖掘、机器学习、深度学习等,
而这些任务都是针对同一个对象——数据。所以,对于数据分析师来说,
学习Python最重要的一个知识点就是如何将外部数据读取到Python当中。
只有数据导进来了,之后才有可能使用Python对数据进行一系列的处理,比如:
- 数据探索( 如导入数据集的形状、简单描述统计 );
- 数据清洗( 如数据类型的转换、缺失值/异常值/重复值的处理、文本数据的处理 );
- 数据汇总( 如数据合并、分组聚合运算、透视表的使用 )等。
首先需要将 pandas 这个模块导入:
python# 约定俗成的导入方式: import numpy as np import pandas as pdpython# 查看版本 pd.__version__ # '2.2.2'
- 文本文件的读取
对于
csv或者txt后缀的文本文件,可以使用pandas模块中的read_csv函数来实现文件的导入。有关
read_csv函数的使用方法和重要参数的含义如下:python# ?pd.read_csvpythonpd.read_csv( filepath_or_buffer, #指定导入文件所在的具体路径 sep=',', #指定原数据中各变量之间的分隔符,默认是逗号,可自行修改 header='infer', #默认将数据集首行作为表头(列名),若原数据集无表头,则设置 header=None names=None, #若原数据集中无变量名称,可通过该参数在数据读取时设定 index_col=None, #指定将某些列作为行索引 usecols=None, #指定需要读取的变量名 converters=None,#通过字典格式,为数据集中的某些变量设置不同的数据类型 skiprows=None, #数据读取时,指定需要跳过原数据集的起始行数 skipfooter=0, #数据读取时,指定需要跳过原数据集的末尾行数 nrows=None, #指定数据读取的行数 comment=None, #指定注释符,读取数据时遇到行首指定的注释符则跳过该行 encoding=None, #设置编码方式,可以通过设置该参数解决中文乱码问题(通常设为"uft-8"或"gbk") )read_csv函数的所有参数及其含义,可以参考pandas官网:
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_csv.html
现在尝试读取一个简单的csv文件:
pythonpd.read_csv(r"data/taobao_data.csv")
| 宝贝 | 价格 | 成交量 | 卖家 | 位置 | |
|---|---|---|---|---|---|
| 0 | 新款中老年女装春装雪纺打底衫妈妈装夏装中袖宽松上衣中年人t恤 | 99.0 | 16647 | 夏奈凤凰旗舰店 | 江苏 |
| 1 | 中老年女装清凉两件套妈妈装夏装大码短袖T恤上衣雪纺衫裙裤套装 | 286.0 | 14045 | 夏洛特的文艺 | 上海 |
| 2 | 母亲节衣服夏季妈妈装夏装套装短袖中年人40-50岁中老年女装T恤 | 298.0 | 13458 | 云新旗舰店 | 江苏 |
| 3 | 母亲节衣服中老年人春装女40岁50中年妈妈装套装夏装奶奶装两件套 | 279.0 | 13340 | 韶妃旗舰店 | 浙江 |
| 4 | 中老年女装春夏装裤大码 中年妇女40-50岁妈妈装夏装套装七分裤 | 59.0 | 12939 | 千百奈旗舰店 | 江苏 |
| ... | ... | ... | ... | ... | ... |
| 95 | 母亲节中老年女装运动服套装中年妈妈春装外套40岁50衣服2017新款 | 368.0 | 4041 | 欧芮嘉旗舰店 | 湖北 |
| 96 | 母亲节衣服中年妈妈装夏装短袖套装30中老年女装春装雪纺衫40岁50 | 181.0 | 4023 | 浅恋旗舰店 | 浙江 |
| 97 | 母亲节妈妈装夏装套装女40-50岁夏季衣服两件套中老年春装连衣裙 | 195.0 | 4000 | 若澜锦蒂旗舰店 | 浙江 |
| 98 | 母亲节衣服夏季中老年女装夏装短袖套装雪纺衫T恤妈妈装两件套 | 498.0 | 3968 | 蕴涵旗舰店 | 江苏 |
| 99 | 中老年女装春装t恤纱袖针织衫40-50岁妈妈装七分袖上衣夏装打底衫 | 688.0 | 3956 | 潮流前线9170 | 浙江 |
100 rows × 5 columns
据读取进来之后形成的表格在pandas中称为
DataFrame( 最常用的 pandas 对象 ),这是一个带有索引的二维数据结构,每一列可以有自己的名字,并且可以有不同的数据类型,
每一行都有索引,数据读取进来的时候默认会生成从0开始的整数索引,
当然,你也可以自行设置每一行的索引。
现在尝试读取一个稍微复杂一点的数据
staff_info.txt,该数据集并不是一个常规的数据集,其存储的内容包含一些其他杂项:

有关该数据集的问题如下:
- 真正的数据部分仅为 4-10 行,在读取数据时需要忽略其他不相关的内容
- 数据中没有变量名(列名),在读取数据时需要加上列名
- 在读取数据时,需要忽略即将离职的两位员工
- 保证员工编号5位数不变
pd.read_csv("data/staff_info.txt"
# 指定原数据分隔符
,sep=","
# 声明原数据没有表头
,header=None
# 指定列名
,names=["编号","姓名","性别","职位"]
# 跳过前两行
,skiprows=2
# 跳过最后两行
,skipfooter=2
# 指定注释符为 “#” 遇到行首为注释符则跳过
,comment="#"
# 指定 “编号”这列为 str 数据类型,则不会去除前置0
,converters={"编号":str}
"""
不设置engine的话会有warning
ParserWarning: Falling back to the 'python' engine
because the 'c' engine does not support skipfooter;
"""
,engine='python'
# 设置编码方式为gbk
,encoding='gbk'
)| 编号 | 姓名 | 性别 | 职位 | |
|---|---|---|---|---|
| 0 | 00446 | 张敏 | 女 | 前端工程师 |
| 1 | 00483 | 李琴 | 女 | Java开发工程师 |
| 2 | 00552 | 赵东来 | 男 | 数据分析师 |
| 3 | 00589 | 丁顺昌 | 男 | 数据分析师 |
- Excel 文件的读取
读取后缀名为
xls/xlsx后缀的Excel电子表格数据,可以使用
read_excel函数,该函数的用法及重要参数含义如下:
pd.read_excel(
io, #指定电子表格的具体路径
sheet_name=0, #指定需要读取excel表格中的第几个sheet,也可以直接写sheet名称
header=0, #默认将首行作为表头
names=None, #若原数据集中无变量名称,可通过该参数在数据读取时设定
index_col=None, #指定将某些列作为行索引
usecols=None, #指定需要读取的变量名
converters=None,#通过字典格式,为数据集中的某些变量设置不同的数据类型
skiprows=None, #数据读取时,指定需要跳过原数据集的起始行数
skipfooter=0, #数据读取时,指定需要跳过原数据集的末尾行数
nrows=None, #指定数据读取的行数
comment=None #指定注释符,读取数据时遇到行首指定的注释符则跳过该行
)尝试读取一个 excel 文件
test.xlsx
pd.read_excel("data/test.xlsx",sheet_name="nam")| Rank | City | State | Population | Date of census/estimate | |
|---|---|---|---|---|---|
| 0 | 1 | London[2] | United Kingdom | 8615246 | 2014-06-01 |
| 1 | 2 | Berlin | Germany | 3437916 | 2014-05-31 |
| 2 | 3 | Madrid | Spain | 3165235 | 2014-01-01 |
| 3 | 4 | Rome | Italy | 2872086 | 2014-09-30 |
| 4 | 5 | Paris | France | 2273305 | 2013-01-01 |
| ... | ... | ... | ... | ... | ... |
| 100 | 101 | Bonn | Germany | 309869 | 2012-12-31 |
| 101 | 102 | Malm枚 | Sweden | 309105 | 2013-03-31 |
| 102 | 103 | Nottingham | United Kingdom | 308735 | 2012-06-30 |
| 103 | 104 | Katowice | Poland | 308269 | 2012-06-30 |
| 104 | 105 | Kaunas | Lithuania | 306888 | 2013-01-01 |
105 rows × 5 columns
二、数据探索
从外部环境将数据集导入到 Python 之后,第一件要做的事就是了解数据,
例如:数据的规模、各变量的数据类型、简单的描述统计、数据中是否存在 缺失值 / 重复值等。
现有某公司用户的个人信息和交易数据,该数据集涉及的变量为用户id、性别、年龄、
受教育程度、交易金额和交易日期。从表面上看,并未看出数据背后可能存在的问题,
接下来尝试将该数据集导入 Python,仔细观察数据集中存在的问题。
# 导入数据集
df = pd.read_excel("data/user_orders.xlsx")# 查看导入数据的前5行
df.head(5)| id | name | gender | age | edu | custom_amt | order_date | |
|---|---|---|---|---|---|---|---|
| 0 | 890 | 李小胆李l | female | 43.0 | NaN | ¥2177.94 | 2018年12月25日 |
| 1 | 2391 | 881xt | male | 52.0 | NaN | ¥2442.18 | 2017年5月24日 |
| 2 | 2785 | haoah | male | 39.0 | NaN | ¥849.79 | 2018年5月15日 |
| 3 | 1361 | snaen | female | 26.0 | NaN | ¥2482.22 | 2018年5月16日 |
| 4 | 888 | sue女少 | female | 61.0 | 本科 | ¥2027.9 | 2018年1月21日 |
# 查看导入数据的后7行
df.tail(3)| id | name | gender | age | edu | custom_amt | order_date | |
|---|---|---|---|---|---|---|---|
| 3001 | 1129 | 小清新桉蓝 | female | 61.0 | NaN | ¥139.68 | 2018年11月7日 |
| 3002 | 674 | xyyx毓 | female | 34.0 | 本科 | ¥670.89 | 2018年6月8日 |
| 3003 | 229 | 大侦探野荒 | male | 64.0 | NaN | ¥118.37 | 2018年7月13日 |
# 查看数据的规模
df.shape
# (3004, 7)# 查看数据行索引
df.index
# RangeIndex(start=0, stop=3004, step=1)# 查看数据列名
df.columns
"""
Index(['id', 'name', 'gender', 'age', 'edu', 'custom_amt', 'order_date'], dtype='object')
"""# 查看整体信息
df.info()
"""
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3004 entries, 0 to 3003
Data columns (total 7 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 id 3004 non-null int64
1 name 3004 non-null object
2 gender 2868 non-null object
3 age 2904 non-null float64
4 edu 1073 non-null object
5 custom_amt 3004 non-null object
6 order_date 3004 non-null object
dtypes: float64(1), int64(1), object(5)
memory usage: 164.4+ KB
"""# 进行简单描述统计
df.describe() #默认统计数值类型| id | age | |
|---|---|---|
| count | 3004.000000 | 2904.000000 |
| mean | 1499.905459 | 41.605028 |
| std | 865.906555 | 14.158348 |
| min | 1.000000 | 19.000000 |
| 25% | 750.750000 | 30.000000 |
| 50% | 1499.500000 | 40.000000 |
| 75% | 2249.250000 | 55.000000 |
| max | 3000.000000 | 230.000000 |
# 查看数据集是否存在缺失值
df.isnull().sum()
"""
id 0
name 0
gender 136
age 100
edu 1931
custom_amt 0
order_date 0
dtype: int64
"""
# ps: is_null() 是缺失值则为True,True计数为1,那么sum()就可以得到缺失值个数# 查看数据集是否存在重复值
df.duplicated().sum()
# 4三、数据选取
探索完数据集之后,我们通常会针对一些特定的数据进行分析或挖掘,
比如针对女性群体研究购物情况;对3月份和4月份产生的交易数据进行对比分析;
仅针对某种支付方式的用户做特征分析等等,这时候就需要对导进来的整个数据集进行筛选,
提取出我们需要的特定数据再进行之后的分析。
# 提取某列
df["gender"]
"""
0 female
1 male
2 male
3 female
4 female
...
2999 female
3000 female
3001 female
3002 female
3003 male
Name: gender, Length: 3004, dtype: object
"""【补充】:
从
DataFrame数据结构中提取出来的单列即为pandas中另一数据类型Series。
Series就是一个带有名称和索引的一维数组。如上面提取出来的这个series,它的名字就是 “gender” ,它的索引就是从0到3003,
这个一维数组中包含数据全部为object类型
(也就是字符串类型,在pandas中除了整型、浮点型和日期型之外的数据类型统称为object类型)
# 提取行
df[5:11] # 左闭右开| id | name | gender | age | edu | custom_amt | order_date | |
|---|---|---|---|---|---|---|---|
| 5 | 2387 | 824bt | male | 42.0 | 本科 | ¥854.57 | 2018年7月6日 |
| 6 | 244 | angil | male | 64.0 | NaN | ¥2661.94 | 2018年8月23日 |
| 7 | 1155 | 280_t | female | 32.0 | NaN | ¥70.66 | 2017年1月6日 |
| 8 | 2623 | ugvuf | male | 48.0 | NaN | ¥2346.97 | 2017年2月11日 |
| 9 | 1782 | 王歆允歆王 | NaN | 60.0 | 本科 | ¥658.3 | 2017年11月15日 |
| 10 | 1714 | 641兔小 | male | 37.0 | NaN | ¥1751.68 | 2018年3月13日 |
如果要 这样的区域数据的话(也就是同时对行和列进行筛选),
上述方式将不再适用。
那可以使用
loc或者iloc的方法进行数据区域的筛选。
- 基于标签的索引—— loc方法
.loc 是基于标签的索引(也可以称为显式索引)大家可以将 loc 中的 l 理解成 "label",
也就是说在loc方法中必须使用数据的标签属性(行标签就是行名称,列标签就是变量名),
否则会返回一个异常。
# 提取数据的5-10行,并返回姓名、年龄和交易金额三列
df.loc[5:10,["name","age","custom_amt"]]| name | age | custom_amt | |
|---|---|---|---|
| 5 | 824bt | 42.0 | ¥854.57 |
| 6 | angil | 64.0 | ¥2661.94 |
| 7 | 280_t | 32.0 | ¥70.66 |
| 8 | ugvuf | 48.0 | ¥2346.97 |
| 9 | 王歆允歆王 | 60.0 | ¥658.3 |
| 10 | 641兔小 | 37.0 | ¥1751.68 |
# 设置某一列作为索引
df1 = df.set_index("name")
df1.head()| id | gender | age | edu | custom_amt | order_date | |
|---|---|---|---|---|---|---|
| name | ||||||
| 李小胆李l | 890 | female | 43.0 | NaN | ¥2177.94 | 2018年12月25日 |
| 881xt | 2391 | male | 52.0 | NaN | ¥2442.18 | 2017年5月24日 |
| haoah | 2785 | male | 39.0 | NaN | ¥849.79 | 2018年5月15日 |
| snaen | 1361 | female | 26.0 | NaN | ¥2482.22 | 2018年5月16日 |
| sue女少 | 888 | female | 61.0 | 本科 | ¥2027.9 | 2018年1月21日 |
# 查看索引
df1.index
"""
Index(['李小胆李l', '881xt', 'haoah', 'snaen', 'sue女少', '824bt', 'angil', '280_t',
'ugvuf', '王歆允歆王',
...
'团90团米', 'xxhyj', '208财招', '是大航oj', '嗒白白嗒蘇', '宝哒哇是我', '和花花豆豆', '小清新桉蓝',
'xyyx毓', '大侦探野荒'],
dtype='object', name='name', length=3004)
"""# 提取["922my","126el","615uy"]三位用户的信息,并返回性别、年龄和学历三列
df1.loc[["922my","126el","615uy"],["gender","age","edu"]]| gender | age | edu | |
|---|---|---|---|
| name | |||
| 922my | female | 29.0 | 本科 |
| 126el | male | 24.0 | 本科 |
| 615uy | female | 35.0 | NaN |
# 提取“李小胆李l”这位用户的全部信息
df1.loc["李小胆李l",:]
"""
id 890
gender female
age 43
edu NaN
custom_amt ¥2177.94
order_date 2018年12月25日
Name: 李小胆李l, dtype: object
"""loc 方法还可以 和 布尔索引 一起连用:
df["age"]<20
"""
0 False
1 False
2 False
3 False
4 False
...
2999 False
3000 False
3001 False
3002 False
3003 False
Name: age, Length: 3004, dtype: bool
"""# 提取出年龄小于20的用户信息
df.loc[df["age"]<20,:]
"""
....运行结果太多..不展示了...
反正就是都满足年龄小于20的信息
"""- 基于位置的索引 —— iloc方法
iloc方法只能通过行号或者列号进行数据的筛选,可以将 iloc 中的 "i" 理解成 "int" ,也就是通过从0开始的位置索引进行筛选。
对于这种方式的索引,第一行或者第一列必须用0表示。
# 提取前5行前3列数据
df.iloc[0:5,0:3]| id | name | gender | |
|---|---|---|---|
| 0 | 890 | 李小胆李l | female |
| 1 | 2391 | 881xt | male |
| 2 | 2785 | haoah | male |
| 3 | 1361 | snaen | female |
| 4 | 888 | sue女少 | female |
# 先查看一下df1的前五行
df1.head()| id | gender | age | edu | custom_amt | order_date | |
|---|---|---|---|---|---|---|
| name | ||||||
| 李小胆李l | 890 | female | 43.0 | NaN | ¥2177.94 | 2018年12月25日 |
| 881xt | 2391 | male | 52.0 | NaN | ¥2442.18 | 2017年5月24日 |
| haoah | 2785 | male | 39.0 | NaN | ¥849.79 | 2018年5月15日 |
| snaen | 1361 | female | 26.0 | NaN | ¥2482.22 | 2018年5月16日 |
| sue女少 | 888 | female | 61.0 | 本科 | ¥2027.9 | 2018年1月21日 |
# 取行索引为 3-5 , 列索引是 1,3,5 ( 跳选 )
df1.iloc[3:6,[1,3,5]]| gender | edu | order_date | |
|---|---|---|---|
| name | |||
| snaen | female | NaN | 2018年5月16日 |
| sue女少 | female | 本科 | 2018年1月21日 |
| 824bt | male | 本科 | 2018年7月6日 |
# 取行索引 4-9 , 所有列
df.iloc[4:10,:]| id | name | gender | age | edu | custom_amt | order_date | |
|---|---|---|---|---|---|---|---|
| 4 | 888 | sue女少 | female | 61.0 | 本科 | ¥2027.9 | 2018年1月21日 |
| 5 | 2387 | 824bt | male | 42.0 | 本科 | ¥854.57 | 2018年7月6日 |
| 6 | 244 | angil | male | 64.0 | NaN | ¥2661.94 | 2018年8月23日 |
| 7 | 1155 | 280_t | female | 32.0 | NaN | ¥70.66 | 2017年1月6日 |
| 8 | 2623 | ugvuf | male | 48.0 | NaN | ¥2346.97 | 2017年2月11日 |
| 9 | 1782 | 王歆允歆王 | NaN | 60.0 | 本科 | ¥658.3 | 2017年11月15日 |
