XieJava's blog

记录最好的自己


  • 首页

  • 分类

  • 标签

  • 归档

  • 关于

pandas数据分析之数据绘图

发表于 2022-02-16 | 更新于: 2025-08-10 | 分类于 技术 , 开发 | | 阅读次数:
字数统计: 2.4k | 阅读时长 ≈ 9

一图胜千言,将信息可视化(绘图)是数据分析中最重要的工作之一。它除了让人们对数据更加直观以外,还可以帮助我们找出异常值、必要的数据转换、得出有关模型的想法等等。pandas 在数据分析、数据可视化方面有着较为广泛的应用。本文将通过实例介绍pandas的数据绘图。
pandas数据绘图

pandas的数据可视化依赖于matplotlib模块的pyplot类,matplotlib在安装Pandas会自动安装。Matplotlib可以对图形做细节控制,绘制出出版质量级别的图形,通过Matplotlib,可以简单地绘制出常用的统计图形。pandas 对 Matplotlib 绘图软件包的基础上单独封装了一个plot()接口,通过调用该接口可以实现常用的绘图操作。
让我们先来认识mataplotlib图形的基本构成。

一、matplotlib图形基本构成

1
2
3
4
import matplotlib.pyplot as plt
import numpy as np
data=np.arange(10)
plt.plot(data)

matplotlib.plot()

通过引入matplotlib模块的pyplot类,将数据传入plot()的接口,就可以将数据以图形化的方式展示出来。Matplotlib 生成的图形主要由以下几个部分构成:
绘图基本结构

  • Figure:指整个图形,您可以把它理解成一张画布,它包括了所有的元素,比如标题、轴线等;
  • Axes:绘制 2D图像的实际区域,也称为轴域区,或者绘图区;
  • Axis:指坐标系中的垂直轴与水平轴,包含轴的长度大小(图中轴长为 7)、轴标签(指 x轴,y轴)和刻度标签;
  • Artist:在画布上看到的所有元素都属于 Artist对象,比如文本对象(title、xlabel、ylabel)、Line2D 对象(用于绘制2D图像)等。

了解matplotlib图形的基本构成非常重要,绘图就是通过matplotlib提供的方法来定义和设置这些基本图形的构成元素来将数据显示在这些元素中。

二、matplotlib显示中文

Matplotlib 默认不支持中文字体,这因为 Matplotlib 只支持 ASCII 字符,但中文标注更加符合中国人的阅读习惯。下面介绍如何在 Windows 环境下让 Matplotlib 显示中文。

1、方法一:临时重写配置文件(临时)

通过临时重写配置文件的方法,可以解决 Matplotlib 显示中文乱码的问题,代码如下所示:

1
2
3
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"]=["SimHei"] #设置字体
plt.rcParams["axes.unicode_minus"]=False #该语句解决图像中的“-”负号的乱码问题

2、方法二:修改配置文件 (永久)

通过直接修改配置文件的方法,可以一劳永逸的解决 Matplotlib 的中文乱码问题。注意此过程在 Windows 环境下进行。
Matplotlib 从配置文件 matplotlibrc 中读取相关配置信息,比如字体、样式等,因此我们需要对该配置文件进行更改。使用如下代码查看 matplotlibrc 所在的目录:

1
2
import matplotlib
matplotlib.matplotlib_fname()

matplotlib_fname

打开配置文件后,找到以下信息:
#font.family: sans-serif
#font.serif: DejaVu Serif, Bitstream Vera Serif, Computer Modern Roman, New Century Schoolbook, Century Schoolbook L, Utopia, ITC Bookman, Bookman, Nimbus Roman No9 L, Times New Roman, Times, Palatino, Charter, serif
修改配置将#注释去掉,并将微软雅黑Microsoft YaHei的字体给加上。
微软雅黑
最后,在windows的字体目录中复制中文字体微软雅黑:
C:\Windows\Fonts\Microsoft YaHei UI
将微软雅黑的字体复制粘贴到matplotlib的字体库中,字体库路径就在matplotlibrc 所在的目录下
D:\Anaconda3\Lib\site-packages\matplotlib\mpl-data\fonts\ttf
复制字体
如果是jupyter notbook重启启动jupyter notbook让它重新读取配置文件即可。

三、pandas绘图

数据分析将数据进行可视化绘图展示离不开数据,pandas的两大数据结构Series和DataFrame都提供了相应的方法很方便的进行数据的可视化绘图展示。

1、数据

pandas 提供了 plot() 方法可以快速方便地将 Series 和 DataFrame 中的数据进行可视化。

a) Series

Series 使用 plot 时 x 轴为索引,y 轴为索引对应的具体值:

1
2
3
4
5
import numpy as np
import pandas as pd
series_data=pd.Series(np.random.randn(10),index=range(10))
series_data
series_data.plot()

Series绘图

b) DataFrame

DataFrame 使用 plot 时 x 轴为索引,y 轴为索引对应的多个具体值:

1
2
3
df_staff = pd.read_excel('D:\\Python\\study\\pythontest\\pandastest\\数据集\\staff_sale_byQ.xlsx')
df_staff
df_staff.plot()

DataFrame绘图
plot()可以通过传入x和y指定显示具体的列数据

1
2
#指定X轴及y显示的列数据
df_staff.plot(x='季度',y=['张三','李四'])

dataframe指定x和y

2、图形

plot 默认为折线图,折线图也是最常用和最基础的可视化图形,足以满足我们日常 80% 的需求。
除了使用默认的线条绘图外,还可以使用其他绘图方式,如下所示:

  • 柱状图:bar() 或 barh()
  • 箱形图:box()
  • 区域图:area()
  • 饼状图:pie()
  • 散点图:scatter()
  • 直方图:hist()

a) 柱状图

柱状图(bar chart),使用与轴垂直的柱子,通过柱形的高低来表达数据的多少,适用于数据的对比,在整体中也能看到数据的发展变化趋势。
DataFrame 可以直接调用 plot.bar() 生成折线图,与折线图类似,x 轴为索引,其他数字类型的列为 y 轴上的条形,可以设置参数stacked=True生成柱状堆叠图
df.plot.bar()
df.plot.barh() # 横向
df[:5].plot.bar(x=’name’, y=’Q4’) # 指定xy轴
df[:5].plot.bar(‘name’, [‘Q1’, ‘Q2’]) # 指定xy轴

1
2
3
4
5
6
#柱状图
df_staff.plot.bar(x='季度',y=['张三','李四','王五'])
#柱状图可以设置参数stacked=True生成柱状堆叠图
df_staff.plot.bar(x='季度',y=['张三','李四','王五'],stacked=True)
#通过barh()方法可以绘制水平柱状图
df_staff.plot.barh(x='季度',y=['张三','李四','王五'],stacked=True)

柱状图

b) 箱形图

箱形图(Box Chart)又称盒须图、盒式图或箱线图,是一种用作显示一组数据分布情况的统计图。Series.plot.box() 、 DataFrame.plot.box(), 和 DataFrame.boxplot() 都可以绘制箱形图。
从箱形图中我们可以观察到:

  • 一组数据的关键值:中位数、最大值、最小值等。
  • 数据集中是否存在异常值,以及异常值的具体数值。
  • 数据是否是对称的。
  • 这组数据的分布是否密集、集中。
  • 数据是否扭曲,即是否有偏向性。
1
df_staff.plot.box(x='季度',y=['张三','李四','王五'])

箱形图

c) 区域图

区域图(Area Chart),又叫面积图。 将折线图中折线与自变量坐标轴之间的区域使用颜色或者纹理填充,这样一个填充区域叫做面积,颜色的填充可以更好的突出趋势信息,需要注意的是颜色要带有一定的透明度,透明度可以很好的帮助使用者观察不同序列之间的重叠关系,没有透明度的面积会导致不同序列之间相互遮盖减少可以被观察到的信息。
面积图默认情况下是堆叠的。 要生成堆积面积图,每列必须全部为正值或全部为负值。

1
df_staff.plot.area(x='季度',y=['张三','李四','王五'])

区域图

d) 饼状图

饼图(Pie Chart)广泛得应用在各个领域,用于表示不同分类的占比情况,通过弧度大小来对比各种分类。饼图通过将一个圆饼按照分类的占比划分成多个区块,整个圆饼代表数据的总量,每个区块(圆弧)表示该分类占总体的比例大小,所有区块(圆弧)的加和等于 100%。
可以使用 DataFrame.plot.pie() 或 Series.plot.pie() 创建饼图

1
2
3
4
5
6
7
df_staff
#看张三每个季度的业绩分布
df_staff.plot.pie(y='张三',subplots=True)
#看第一个季度,每个人的绩效分布
df_staff1=df_staff.loc[0:0,'张三':'孙八'].T
df_staff1.columns=['Q']
df_staff1.plot.pie(y='Q',subplots=True)

饼图

e) 散点图

散点图(Scatter graph)也叫 X-Y 图,它将所有的数据以点的形式展现在直角坐标系上,以显示变量之间的相互影响程度,点的位置由变量的数值决定。
通过观察散点图上数据点的分布情况,我们可以推断出变量间的相关性。如果变量之间不存在相互关系,那么在散点图上就会表现为随机分布的离散的点,如果存在某种相关性,那么大部分的数据点就会相对密集并以某种趋势呈现。

1
2
df1 = pd.DataFrame(np.random.rand(50, 4), columns=["a", "b", "c", "d"])
df1.plot.scatter(x="a", y="b");

散点图

f) 直方图

直方图(Histogram),又称质量分布图,是一种统计报告图,它是根据具体数据的分布情况,画成以组距为底边、以频数为高度的一系列连接起来的直方型矩形图。
直方图说明

1
2
3
4
5
6
7
8
9
10
11
#构建数据集
df4=pd.DataFrame({
"a": np.random.randn(1000) + 1,
"b": np.random.randn(1000),
"c": np.random.randn(1000) - 1,
"d": np.random.randn(1000) - 2,
},columns=['a','b','c','d'])
df4
df4.plot.hist(alpha=0.5) #指定图形透明度
df4.plot.hist(stacked=True,bins=20) #堆叠并指定箱数为20
df4.diff().hist() #通过diff给每一列数据都绘制一个直方图

直方图

至此,本文介绍了pandas常用的绘图组件matplotlib,包括mataplotlib绘图的基本构成,如何在windows下解决中文问题,并通过实例介绍了如何通过pandas的数据集绘制折线图、箱线图、柱状图、饼图、面积图、散点图、直方图等。

参考资料:《利用python进行数据分析》、pandas官网 user guide

数据集及源代码见:https://github.com/xiejava1018/pandastest.git


作者博客:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

pandas数据分析之数据重塑透视(stack、unstack、melt、pivot)

发表于 2022-02-14 | 更新于: 2025-08-10 | 分类于 技术 , 开发 | | 阅读次数:
字数统计: 2k | 阅读时长 ≈ 7

在数据分析的过程中,分析师常常希望通过多个维度多种方式来观察分析数据,重塑和透视是常用的手段。
数据的重塑简单说就是对原数据进行变形,为什么需要变形,因为当前数据的展示形式不是我们期望的维度,也可以说索引不符合我们的需求。对数据的重塑不是仅改变形状那么简单,在变形过程中,数据的内在数据意义不能变化,但数据的提示逻辑则发生了重大的改变。
数据透视是最常用的数据汇总工具,Excel 中经常会做数据透视,它可以根据一个或者多个指定的维度来聚合数据。pandas 也提供了数据透视函数来实现这些功能。
如果能熟练区分和使用各种重塑和透视分析方法,那用pandas处理分析日常的数据基本上就没有什么难度了。

重塑和透视

在介绍数据重塑透视之前,先来介绍一下pandas中DataFrame的层次化索引,它广泛应用于重塑透视操作。

一、层次化索引

层次化索引是pandas的一项重要功能,它使你能在一个轴上拥有多个(两个以上)索引层数,分层索引的目的是用低维度的结构(Series 或者 DataFrame)更好地处理高维数据。通过分层索引,我们可以像处理二维数据一样,处理三维及以上的数据。分层索引的存在使得分析高维数据变得简单。
我们来看一下student数据集,并根据该数据集分别构建列和行的层次索引。然后再介绍数据的重塑和透视。
引入student数据集:

1
2
3
4
import numpy as np
import pandas as pd
df = pd.read_excel('D:\\Python\\study\\pythontest\\pandastest\\数据集\\student.xlsx')
df

student数据集

该student数据集包含学生学号、姓名、语文、数据、英语的成绩等。

1、列索引分层

我们选取一些关键的数据构建列标签的层次化索引。这里我们选取’班级’,’姓名’,’语文’,’数学’,’英语’的列,并且将‘班级’、‘姓名’标记为‘标识’,’语文’,’数学’,’英语’标记为‘成绩’

1
2
3
df_student=df[['班级','2-姓名','4-语文','5-数学','6-英语']]
df_student.columns=[['标识','标识','成绩','成绩','成绩'],['班级','姓名','语文','数学','英语']]
df_student

列索引分层
通过指定DataFrame的columns的层级将’班级’,’姓名’,’语文’,’数学’,’英语’,上多抽出了一个层级,这个层有两个索引一个是‘标识’,一个是成绩,其中‘班级’和‘名称’是属于标识,’语文’,’数学’,’英语’都是’成绩’。

2、行索引分层

接下来看行索引的分层。我们将属于一班的和属于二班的同学进行分层,再分成两个索引。

1
2
3
4
#根据行索引分层,设置行索引将其分成班级和姓名两个层次索引
df_student=df_student.set_index([('标识','班级'),('标识','姓名')])
df_student.index.names=['班级','姓名']
df_student

行索引的分层

可以看到将数据集的班级和姓名列分成了两个行的层级索引。没有用默认的0-9的行索引

二、数据堆叠与拆堆

层次化索引为DataFrame数据的重排任务提供了一种具有良好一致性的方式,有许多用于重新排列表格数据的基础运算。这些函数也称作重塑(reshape)或轴向旋转(pivot)运算。
常见的数据重塑包括数据的堆叠 stack 和 取消堆叠 unstck

1、数据堆叠 stack

堆叠 stack ,顾名思义,就是将列的数据堆叠形成行。
借用pandas官网的示意图:
堆叠 stack

看实际数据数据会更容易理解,为了方便我们取student数据集的前5行记录来进行数据堆叠stack()

1
2
3
4
5
df_student[:5]
#将数据进行堆叠
#将数据进行堆叠
df_student5=df_student[:5].stack()
df_student5

堆叠 stack()

在这里可以看到通过stack()将“语文”、“数学”、”英语”,三列,一个个堆叠形成一条记录的三行。这样列数减少了,行数增多了。

stack()

对于多层索引,可以根据指定堆叠层次,默认是最高层次的堆叠。
我们来看指定堆叠层次,如果stack(0),表示堆叠level0层的。

分层堆叠

2、取消堆叠 unstack

取消堆叠 unstack是堆叠的反操作。
Unstack

也就是将堆叠好了的行数据,一个个卸下来形成列。这样一来行数减少了,但是列数增多了。

1
2
# 取消堆叠 unstack()
df_student5.unstack()

unstack

可以看到原来的“语文”、“数学”、”英语”三行,通过unstack()进行拆堆,拆成了三列,明显数据没有那么高了,行数少了,列数多了。
unstack

同样对于多层索引可以逐层拆堆
逐层拆堆

三、数据融合与透视

数据透视是最常用的数据汇总工具,它可以根据一个或者多个指定的维度来聚合数据。实际上搞懂了stack和unstack就很容易搞懂pivot和melt了,stack和unstack根据索引来进行堆叠和拆堆,pivot和melt可以根据指定的数据来进行变换操作灵活性更高。

1、数据融合 melt

来看pandas官网的示意图,是不是和stack的图有点类似,都是将列转换成行,不同的是melt可以指定哪些列固定,哪些列转换成行等灵活性更高。简单说就是将指定的列放到铺开放到行上名为variable(可指定)列,值在value(可指定)列
melt
melt语法:

1
2
3
4
pd.melt(frame: pandas.core.frame.DataFrame,
id_vars=None, value_vars=None,
var_name='variable', value_name='value',
col_level=None)

其中:

  • id_varstuple,list或ndarray(可选),用作标识变量的列。
  • value_varstuple,列表或ndarray,可选,要取消透视的列。 如果未指定,则使用未设置为id_vars的所有列。
  • var_namescalar,用于“变量”列的名称。 如果为None,则使用frame.columns.name或“variable”。
  • value_namescalar,默认为“ value”,用于“ value”列的名称。
    • col_levelint或str,可选,如果列是MultiIndex,则使用此级别来融化。

我们还是来看示例:
数据集还是student数据集,为了演示方便取前5条记录

1
2
3
df_student=df[['班级','2-姓名','4-语文','5-数学','6-英语']]
df_student.columns=[['标识','标识','成绩','成绩','成绩'],['班级','姓名','语文','数学','英语']]
df_student[0:5]

melt

现在将“班级”和“姓名”固定,’语文’,’数学’,’英语’三列转换成行融合为“学科”字段,这三个列的值定义为“分数”列。

1
2
3
4
5
# 将“班级”和“姓名”固定,'语文','数学','英语'三列转换成行融合为“学科”字段,这三个列的值定义为“分数”列
df_student[0:5].melt(id_vars=['班级','姓名'],
value_vars=['语文','数学','英语'],
var_name='学科',
value_name='分数',col_level=1)

melt
具体实现如下图所示:
melt

2、数据透视 pivot

来看pandas官网的示意图,是不是和unstack的图有点类似,将行数据转换成列。同样pivot提供了更多的参数可以指定相应的数据进行转换,比unstack更加灵活。
pivot

这里有三个参数,作用分别是:

  • index:新 df 的索引列,用于分组,如果为None,则使用现有索引
  • columns:新 df 的列,如果透视后有重复值会报错
  • values:用于填充 df 的列。 如果未指定,将使用所有剩余的列,并且结果将具有按层次结构索引的列
1
2
3
4
5
6
df_student5=df_student[0:5].melt(id_vars=['班级','姓名'],
value_vars=['语文','数学','英语'],
var_name='学科',
value_name='分数',col_level=1)
df_student5
df_student5.pivot(index=['班级','姓名'],columns='学科',values='分数')

pivot

这里通过pivot将“学科”的行数据透视转换成“数学”、“英语”、“语文”三列,具体实现如下图所示:
privot
可以看出privot实际和unstack类似是由行转换成列的视图,但比起unstack更加灵活。

至此,介绍了pandas的多层索引及pandas的4种重塑操作:stack、unstack、pivot、melt:
stack、unstack是基础:stack实现列转行,unstack实现行转列。
melt与stack类似,比stack更加灵活。
pivot与unstack类似,比unstack更加灵活。

数据集及源代码见:https://github.com/xiejava1018/pandastest.git


作者博客:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

pandas数据分析之分组聚合

发表于 2022-02-12 | 更新于: 2025-08-10 | 分类于 技术 , 开发 | | 阅读次数:
字数统计: 1.8k | 阅读时长 ≈ 7

在数据分析过程中,经常会需要根据某一列或多列把数据划分为不同的组别,然后再对其进行数据分析。本文将介绍pandas的数据分组及分组后的应用如对数据进行聚合、转换和过滤。

分组聚合

在关系型数据库中我们常用SQL的GROUP BY操作进行分组分析计算。在pandas中要完成数据的分组操作同样可用groupby()函数,然后再在划分出来的组(group)上应用一些统计函数,从而达到数据分析的目的,比如对分组数据进行聚合、转换或者过滤。这个过程主要包含以下三步:拆分(split)-应用(apply)-合并(combine)
例如,DataFrame可以在列(axis=1)或行(axis=0)上进行分组(split),然后将一个函数应用(apply)到各个分组并产生一个新值,最后所有这些函数的执行结果会被合并(combine)到最终的结果对象中。
一个简单的分组聚合的过程如下图所示:
拆分(split)-应用(apply)-合并(combine)

我们来构造图中所示的DataFrame数据集,看看pandas的分组聚合是怎么做的。

1
2
3
4
import pandas as pd
import numpy as np
df=pd.DataFrame({'key':['A','B','C','A','B','C','A','B','C'],'data':[0,5,10,5,10,15,10,15,20]})
df

数据集

1
2
3
4
5
grouped=df.groupby(['key']) #通过key分组
#查看分组情况
for dtype,group in grouped:
print(dtype)
grouped.sum() #对每个分组应用sum函数,并最后组合成结果

对df的key进行用groupby()进行分组
通过对df的key进行用groupby()进行分组,这里可看到,将数据分成了A、B、C三组,然后对这三组分别应用sum()函数求和,再组合成最终的结果。
对于分组聚合一般来说实际上是分两步:一是创建分组对象进行分组,二是对分组进行相应处理如(对组应用聚合函数、对组进行转换、对组的数据进行过滤)。不过实际在具体写的时候可以通过链式调用一个语句就可以实现如:

1
df.groupby(['key']).sum() #链式调用先分组再用聚合函数聚合

链式调用先分组再用聚合函数聚合

一、创建分组对象进行分组

groupby可以把分组时指定的键(key)作为每组的组名。groupby对象支持迭代,可以遍历每个分组的具体数据。
如:

1
2
3
4
#查看分组情况
for name,group in grouped:
print(name)
print(group)

查看分组情况

1、根据多列进行分组

groupby可以通过传入需要分组的参数实现对数据的分组,参数可以是单列,也可以是多列,多列以列表的方式传入。

1
grouped=df.groupby(['key1','key2'])

多列进行分组

2、通过字典或Series进行分组

除数组以外,分组信息还可以其他形式存在。如可以定义字典或Series进行分组。

1
2
3
4
5
6
7
8
9
10
people=pd.DataFrame(np.random.randn(5,5),
columns=['a','b','c','d','e'],
index=['Joe','Steve','Wes','Jim','Bob'])
people
mapping={'a':'red','b':'red','c':'blue','d':'blue','e':'red'}#定义分组字典
by_column=people.groupby(mapping,axis=1)
#查看分组情况
for group_name,group_data in by_column:
print(group_name)
print(group_data)

字典分组

在字典中我们定义了mapping={'a':'red','b':'red','c':'blue','d':'blue','e':'red'}#定义分组字典
a、b、e对应“red”,c、d对应“blue”所以将blue和red分成了两组。
sum聚合

应用sum()求和函数,可以看到分别对blue和red的分组进行了求和。
类似的,Series也是一样的,我们将map转换成Series,可以看到分组结果和map分组一样的。
Series分组

3、通过函数进行分组

比起使用字典或Series,使用Python函数是一种更原生的方法定义分组映射,。任何被当做分组键的函数都会在各个索引值上被调用一次,其返回值就会被用作分组名称。
如上面的people数据集,将姓名索引的长度进行分组。

1
by_len=people.groupby(len)

by_len

可以看到将姓名长度相同的3分成一组,长度为5的数据分成了一组
更加通用的是可以自定义函数进行分组,如要将索引>5的和小于5的分别分组,可以自定义函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#数据集
df=pd.DataFrame({'key':['A','B','C','A','B','C','A','B','C'],
'data':[0,5,10,5,10,15,10,15,20]},
index=[1,2,3,4,5,6,7,8,9])
df
#自定义函数区分大于5和小于5的数据
def big5(x):
result=0
if x>5:
result=1
return result

by_big5=df.groupby(big5) #根据索引是否大于5进行分组
#查看分组情况
for group_name,group_data in by_big5:
print(group_name)
print(group_data)

自定义函数分组

二、对分组后的数据进行应用

前面通过分组将数据集根据条件分组后,可以对分组后的数据进行各种处理包括聚合、转换、过滤等操作。

1、对分组数据用聚合函数进行聚合

a) 使用pandas聚合函数

前面第一部分的例子中对数据分组后进行了sum()求和聚合操作,类似的聚合函数还有很多如:

函数名 描述
count 分组中非NA值的数量
sum 非NA值的和
mean 非NA值的平均值
median 非NA值的中位数
std, var 标准差和方差
min, max 非NA的最小值,最大值
prod 非NA值的乘积
first, last 非NA值的第一个,最后一个

聚合函数

b) 使用自定义聚合函数

pandas的groupby分组对象还可以用自定义的聚合函数可以通过groupby分组对象,将你自己的聚合函数,传入aggregate或agg方法即可

1
2
df=pd.DataFrame({'key':['A','B','C','A','B','C','A','B','C'],'data':[0,5,10,5,10,15,10,15,20]})
df

数据集

1
2
3
4
5
grouped=df.groupby(['key'])
#查看分组情况
for group_name,group_data in grouped:
print(group_name)
print(group_data)

分组情况

1
2
3
4
def peak_to_peak(arr):
return arr.max() - arr.min()

grouped.agg(peak_to_peak)

自定义函数分组

2、根据分组数据进行转换

根据分组数据进行数据转换或其他操作,可以在分组的基础上用apply函数进行数据的转换。
如数据集

1
2
3
4
5
6
7
8
9
df=pd.DataFrame({'key':['A','B','C','A','B','C','A','B','C'],
'data':[0,5,10,5,10,15,10,15,20]})
df
根据key分组
grouped=df.groupby(['key'])
#查看分组情况
for group_name,group_data in grouped:
print(group_name)
print(group_data)

数据集

现在我们要对data求和后小于25的分组数据都加1
那么我们可以定义函数,然后再对分数数据进行应用

1
2
3
4
5
6
def add1(df):
if df[:]['data'].sum()<25:
return df[:][['data']]+1
else:
return df[:][['data']]
grouped.apply(add1)

数据转换

3、根据分组数据进行过滤

通过 filter() 函数可以实现数据的筛选,该函数根据定义的条件过滤数据并返回一个新的数据集。
如当我们要过滤掉分组后data求和小于25的数据

1
2
3
4
5
6
7
#过滤掉sum()求和小于25的数据
def filtersum25(x):
if x['data'].sum()>25:
return True
else:
return False
grouped.filter(filtersum25)

数据过滤

至此,本文通过实例介绍了pandas的数据分组及分组后的应用如对数据进行聚合、转换和过滤。数据的分组和聚合是数据分析中常用的分析手段,转换和过滤是数据处理中可用到的方法。

数据集及源代码见:https://github.com/xiejava1018/pandastest.git


作者博客:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

pandas数据处理之合并与拼接

发表于 2022-02-10 | 更新于: 2025-08-10 | 分类于 技术 , 开发 | | 阅读次数:
字数统计: 2.7k | 阅读时长 ≈ 10

在许多应用中,数据可能来自不同的渠道,在数据处理的过程中常常需要将这些数据集进行组合合并拼接,形成更加丰富的数据集。pandas提供了多种方法完全可以满足数据处理的常用需求。具体来说包括有join、merge、concat、append等。

合并与拼接

一般来说

方法 说明
join 最简单,主要用于基于索引的横向合并拼接
merge 最常用,主要用户基于指定列的横向合并拼接
concat 最强大,可用于横向和纵向合并拼接
append 主要用于纵向追加
combine_first 合并重叠数据,填充缺失值
update 将一个数据集的值更新到另一个数据集

下面就来逐一介绍每个方法

一、join

join主要用于基于索引的横向合并拼接
在介绍pandas的join之前我们来看一下SQL对数据集join的几种模式。如果大家对SQL比较熟悉的话应该对SQL操作数据集进行各种合并拼接印象深刻。SQL中各种JOIN的方法如下:
SQL-JOIN

pandas的join实现了left join、right jion、inner join、out jion常用的4中join方法
来自官网的参数说明:

1
2
3
4
5
6
dataframe.join(other,  # 待合并的另一个数据集
on=None, # 连接的键
how='left', # 连接方式:‘left’, ‘right’, ‘outer’, ‘inner’ 默认是left
lsuffix='', # 左边(第一个)数据集相同键的后缀
rsuffix='', # 第二个数据集的键的后缀
sort=False) # 是否根据连接的键进行排序;默认False

我们来看下实例,有两个数据集一个是人员姓名,一个是人员的工资

1
2
left=pd.DataFrame(['张三','李四','王五','赵六','钱七'], index=[3,4,5,6,7],columns=['姓名'])
right=pd.DataFrame([13000,15000,9000,8600,10000], index=[3,4,5,6,8],columns=['工资'])

数据集

注意,left和right的数据集分别都指定了index,因为join主要用于基于索引的横向合并拼接。

1、left join

1
left.join(right)  #默认how='left'

left join

jion操作默认是left jion的操作,可以看到left索引为7姓名为钱七,在right中没有索引为7的对应所以显示left的姓名但right的工资为NaN,right中索引为8的数据在left中没有索引为8的,所以没有显示。left join合并left的数据
left join 如下图所示
left join

2、right join

1
left.join(right,how='right')

right join

右链接合并时可以看到,left的数据集没有索引为8的项,所以索引为8的项显示right数据集的工资数据但姓名为NaN,在left中索引为7的项因为right中不存在,所以没有显示。right join合并right的数据
right join 如下图所示
right join

3、inner join

1
left.join(right,how='inner')

inner join

内链接合并时,可以看到left数据集中的索引为7姓名为钱七因为在right数据集中找不到对应的索引,right数据集中索引为8的在left找不到对应的索引所以内连接合并时索引7和8都没有进行合并,inner join只合并两个数据集共有的数据
inner join 如下图所示
inner join

4、out join

1
left.join(right,how='outer')

out join
外链接合并时,可以看到不管是left中的数据还是right中的数据都进行了合并。right join合并两个数据集中所有的数据。
outer join 如下图所示
outer join
join很简单,但是它有局限性,因为它只能根据索引来合并。不能指定键来进行合并。比如我要根据编号和姓名来合并,join就比较难办了。但是pandas提供了merge的方法,可以指定列来进行合并拼接。

二、merge

merge最常用,主要用户基于指定列和横向合并拼接,语法如下:

1
2
pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None,
left_index=False, right_index=False, sort=True,suffixes=('_x', '_y'), copy=True)
参数名称 说明
left/right 两个不同的 DataFrame 对象。
on 指定用于连接的键(即列标签的名字),该键必须同时存在于左右两个 DataFrame 中,如果没有指定,并且其他参数也未指定, 那么将会以两个 DataFrame 的列名交集做为连接键。
left_on 指定左侧 DataFrame 中作连接键的列名。该参数在左、右列标签名不相同,但表达的含义相同时非常有用。
right_on 指定左侧 DataFrame 中作连接键的列名。
left_index 布尔参数,默认为 False。如果为 True 则使用左侧 DataFrame 的行索引作为连接键,若 DataFrame 具有多层索引(MultiIndex),则层的数量必须与连接键的数量相等。
right_index 布尔参数,默认为 False。如果为 True 则使用左侧 DataFrame 的行索引作为连接键。
how 要执行的合并类型,从 {‘left’, ‘right’, ‘outer’, ‘inner’} 中取值,默认为“inner”内连接。
sort 布尔值参数,默认为True,它会将合并后的数据进行排序;若设置为 False,则按照 how 给定的参数值进行排序。
suffixes 字符串组成的元组。当左右 DataFrame 存在相同列名时,通过该参数可以在相同的列名后附加后缀名,默认为(‘_x’,’_y’)。
copy 默认为 True,表示对数据进行复制。

我们来看下面的数据集,在上面的数据集中left数据集加入了员工的编号,right数据集加入了编号及姓名。索引就按默认的索引。

1
2
3
4
5
left=pd.DataFrame([[3,'张三'],[4,'李四'],[5,'王五'],[6,'赵六'],[7,'钱七']],
columns=['编号','姓名'])

right=pd.DataFrame([[3,'张三',13000],[4,'李四',15000],[5,'王五',9000],[6,'赵六',8600],[8,'孙八',10000]],
columns=['编号','姓名','工资'])

merge数据集

1
pd.merge(left,right)

pd.merge(left,right)

没有指定连接键,默认用重叠列名,没有指定连接方式,默认inner内连接(取left和right编号和姓名的交集)
和join一样通过how来指定连接方式如:

1
pd.merge(left,right,how='left')

pd.merge(left,right,how='left')

how的连接方式和join一样支持left、right、inner、outer
merge还可以指定多个列进行合并链接,也就是和SQL一样设置多个关联的列。

1
pd.merge(left,right,how='outer',on=['编号','姓名'])

merge-out

如果两个对象的列名不同,可以使用left_on,right_on分别指定,如我们把right数据集的“编码”列标签改成“ID”后如果需要left数据集的”编号”和right数据集的”ID”进行关联

1
2
3
right=pd.DataFrame([[3,'张三',13000],[4,'李四',15000],[5,'王五',9000],[6,'赵六',8600],[8,'孙八',10000]],columns=['ID','姓名','工资'])

pd.merge(left,right,how='outer',left_on='编号',right_on='ID')

指定列名关联

虽然说merge已经很强大了,但是pandas愿意给你更多,它提供了concat,可以实现横向和纵向的合并与拼接。也就是说不但实现了SQL中的join还实现了union

三、concat

concat() 函数用于沿某个特定的轴执行连接操作,语法如下:

1
pd.concat(objs,axis=0,join='outer',join_axes=None,ignore_index=False)
参数名称 说明
objs 一个序列或者是Series、DataFrame对象。
axis 表示在哪个轴方向上(行或者列)进行连接操作,默认 axis=0 表示行方向。
join 指定连接方式,取值为{“inner”,”outer”},默认为 outer 表示取并集,inner代表取交集。
ignore_index 布尔值参数,默认为 False,如果为 True,表示不在连接的轴上使用索引。
join_axes 表示索引对象的列表。

来看具体的例子

1
left2=pd.DataFrame([[1,'陈一'],[2,'周二']],columns=['编号','姓名'])

数据集

1、纵向合并

concat默认纵向拼接,我们要在left1数据集的基础上把left2数据集给合并上去,很简单用concat直接就可以合并。

1
df=pd.concat([left,left2])

纵向合并

2、横向合并

1
2
df_outer=pd.concat([left,right],axis=1,join='outer')#外链接
df_inner=pd.concat([left,right],axis=1,join='inner')#内链接

横向合并

注意:因为concat的链接和join一样是通过索引来链接合并,并不能指定通过某个特定的列来链接进行合并,所以看到的合并后的数据集left和right的编号和姓名是错位的。

如果要根据编号来关联可以指定编号作为索引再进行横向合并,这样就没有问题了。

1
2
3
4
left.index=left['编号'].values
right.index=right['编号'].values
df_outer=pd.concat([left,right],axis=1,join='outer')
df_inner=pd.concat([left,right],axis=1,join='inner')

横向合并

四、append

df.append 可以将其他行附加到调用方的末尾,并返回一个新对象。它是最简单常用的数据合并方式。语法如下:

1
df.append(self, other, ignore_index=False,verify_integrity=False, sort=False)

其中:

  • other 是它要追加的其他 DataFrame 或者类似序列内容
  • ignore_index 如果为 True 则重新进行自然索引
  • verify_integrity 如果为 True 则遇到重复索引内容时报错
  • sort 进行排序

来看下面的例子:

1、同结构数据追加

将同结构的数据追加在原数据后面,在left数据集后面追加left2数据集,left2的数据集内容如下:

1
2
left2=pd.DataFrame([[1,'陈一'],[2,'周二']],columns=['编号','姓名'])
left2

append数据集

1
left.append(left2)

append

2、不同结构数据追加

不同结构数据追加,原数据没有的列会增加,没有对应内容的会为空NaN。
如:left3的数据集列有”编号”、”姓名”、”工资”

1
2
left3=pd.DataFrame([[8,'孙八',10000],[9,'何九',15000]],columns=['编号','姓名','工资'])
left3

left3的数据集

1
left.append(left3)

不同结构数据追加

当left后追加left3后的数据集会增加“工资列”,没有对应内容的会为空。

3、追加合并多个数据集

append参数可带数据集列表,可以将多个数据集追加到原数据集
如我们将left2和left3都追加到left

1
left.append([left2,left3])

追加合并多个数据集

五、combine_first

combine_first可用于合并重复数据,用其他数据集填充没有的数据。如一个DataFrame数据集中出现了缺失数据,就可以用其他DataFrame数据集中的数据进行填充。语法格式如下:

1
combine_first(other) #只有一个参数other,该参数用于接收填充缺失值的DataFrame对象。

如left数据集中没有”工资”的数据,我们可以用right数据集有的数据去填充left数据集中的数据。

1
left.combine_first(right) #用right去填充left

combine_first

六、update

update和combine_first比较类似,区别在于:
1、填充合并方式稍有差异
combine_first:如果s1中c的值为空,用s2的值替换,否则保留s1的值
update:如果s2中的值不为空,那么替换s1,否则保留s1的值
2、update是更新原数据,combine_first会返回一个填充后的新数据集,对原数据不做更新。

1
left.update(right) #用right的数据更新left中的数据。

update

至此,本文介绍了pandas的多种数据合并与拼接方法,并介绍了每种方法的异同,通过pandas的数据处理可以应付日常数据处理中大部分的数据处理工作。

数据集及源代码见:https://github.com/xiejava1018/pandastest.git


作者博客:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

pandas基本操作之数据访问(查看与检索)

发表于 2022-02-07 | 更新于: 2025-08-10 | 分类于 技术 , 开发 | | 阅读次数:
字数统计: 1.8k | 阅读时长 ≈ 7

对于数据分析来说,在构造或载入数据后最基本的操作应该就是对数据的访问了。看一看数据的结构、组成、分布等,根据需要从数据集中检索提取出相应的数据。pandas作为数据分析的利器,当然提供了多种查看和检索数据的方法。本文就来捋一捋pandas基本的数据访问。

数据访问

一、查看数据

当我们拿到数据集后,第一步可能就是查看数据了,一方面是了解拿到的数据集的数据结构,另一方面随机检查一下数据的质量问题。
不管是Series还是DataFrame的数据集pandas常用的数据查看方法有:

方法 操作 结果
head(n) 查看数据集对象的前n行 Series或DataFrame
tail(n) 查看数据集的最后n行 Series或DataFrame
sample(n) 随机查看n个样本 Series或DataFrame
describe() 数据集的统计摘要 Series

以下就以一个DataFrame数据集为例来看看这些查看数据的方法。

1
2
3
4
import numpy as np
import pandas as pd
df = pd.read_excel('D:\\Python\\study\\pythontest\\pandastest\\数据集\\staff.xlsx')
df

studend数据集

1、查看头部 head(n)

head()方法如果不带参数,默认返回前5条记录,带了参数n就返回前n条记录。

1
2
df.head() #默认查看前5条记录
df.head(8) #指定查看前8条记录

查看头部 head(n)

2、查看尾部 tail(n)

同样tail()方法如果不带参数,默认返回后面5条记录,带了参数n就返回后面n条记录。

1
2
df.tail() #默认查看后面5条记录
df.tail(4) #指定查看后面4条记录

查看尾部 tail(n)

3、随机查看样本 sample(n)

sample() 不带参数会随机返回一条样本数据,带了参数n就会随机返回n条记录。

1
2
df.sample() #随机查看一条记录
df.sample(4) #随机查看4条记录

随机查看样本 sample(n)

4、查看统计摘要

df.describe() 返回所有数字列的统计摘要。
查看统计摘要

这里连staff_id的统计摘要就显示出来了,因为它是数字列。如果只看某一列的统计摘要

1
df[['staff_salary']].describe()

只看某一列的统计摘要

二、检索数据

在数据分析过程中,很多时候需要从数据表中提取出相应的数据,而这么做的前提是需要先“检索”出这一部分数据。虽然通过 Python 提供的索引操作符”[]”和属性操作符”.”可以访问 Series 或者 DataFrame 中的数据,但这种方式只适应与少量的数据,为了解决这一问题,pandas 提供了多种类型的索引方式来实现数据的访问。包括[]、loc\iloc、at\iat、布尔索引
一般的:
df[‘name’] #会返回本列的Series
df.name #也会返回本列的Series

但是要注意,name应该是一个合法的python变量时才可以直接作为属性来使用。

如:
df[‘1级别’]可以正常返回索引列为“1级别”的数据,而df.1级别会报错,因为”1级别”不是一个合法的python变量。
列索引检索
以下通过DataFrame数据集来说明常用检索数据的方法。对于DataFrame的数据集来说要检索数据通常是确定数据所在的行和列。而确定行和列也有两种方式,一是通过标签索引来确定,二是通过数据所在的位置来确定。
一般的:

操作 语法 返回结果
选择列 df[col] Series
按索引选择行 df.loc[label] Series
按位置选择行 df.iloc[loc] Series
使用切片选择行 df[2:5] DataFrame
用表达式筛选行 df[bool] DataFrame

1、切片[]

通过[]进行检索,这将会对行进行切片

1
df[0:3] #通过切片检索行数据

在这里插入图片描述

切片并不对列有效,如果是df[0:3][1:2],会检索出0-3行,再在这三行切片的基础上切片中检索出第二行。
df[0:3][1:2]

如果要在切片检索的结果上再选择列,则可以通过列标签索引列表来选择

1
df[0:3][['staff_id','staff_name','staff_gender']] #通过列标签索引列表检索列数据

通过列标签索引列表来选择

2、loc\iloc

loc

df.loc[] 只能使用标签索引,不能使用位置索引。当通过标签索引的切片方式来筛选数据时,它的取值前闭后闭,也就是只包括边界值标签(开始和结束)
.loc[] 具有多种访问方法,如下所示:

  • 一个标量标签
  • 标签列表
  • 切片对象
1
2
3
4
5
df.loc[1] #标量标签,返回该行标签的Series数据
df.loc[[1,3]] #标签列表,返回标签列表的行DataFrame数据
df.loc[0:3] #切片对象,返回切片的行DataFrame数据
df.loc[0:3,'staff_id':'staff_salary'] #根据行切片,列切片检索数据
df.loc[[0,1,2,3],['staff_id','staff_name','staff_age']] #根据行标签列表,列标签列表检索数据

loc

.loc[] 除了标量标签,标签列表和切片对象都接受两个参数,并以’,’分隔。第一个位置表示行检索,第二个位置表示列检索
loc2

iloc

df.iloc[] 只能使用位置索引(用整数表示所在行或列的位置如第几行第几列),不能使用标签索引,通过整数索引切片选择数据时,前闭后开(不包含边界结束值)。同 Python 和 NumPy 一样,它们的索引都是从 0 开始
.iloc[] 提供了以下方式来选择数据:

  • 整数索引
  • 整数列表
  • 数值范围

为了说明方便,我们把数据集的行索引重名为字母

1
2
df=df.rename(index={0:'A',1:'B',2:'C',3:'D',4:'E',5:'F',6:'G',7:'H',8:'I',9:'J'})
df

reanme

1
2
3
4
df.iloc[1]  #整数标量选择,数据从0开始,为1的就是第二行的数据,返回的是Series
df.iloc[[1,3]] #整数列表选择,选择位置为1和3的数据,返回的是DataFrame
df.iloc[1:3] #切片选择,选择位置1至2的数据,不包含边界结束值,也就是不包含3的位置
df.iloc[1:3,1:4] #切片选择位置为1至3的行和1至4的列不含位置为3的行和位置为4的列

iloc

3、at\iat

at和iat和loc和iloc类似,不同的是at和iat仅取一个具体的值,结构为 at[<索引>,<列名>],iat[<行位置>,<列位置>]

1
2
df.at['A','staff_name']  #检索第“A”行的列标签为"staff_name"的数据
df.iat[0,1] #检索第1行第2列的数据

at\iat

4、布尔条件检索

1、[] 里用布尔条件进行检索

如:

1
df[(df.staff_salary>10000)&(df.staff_age<40)]  #检索staff_age小于40且staff_salary>10000的数据

[] 里用布尔条件进行检索

2、loc索引部分用布尔条件检索

如:

1
df.loc[(df.staff_salary>10000)&(df.staff_age<40)]  #检索staff_age小于40且staff_salary>10000的数据

loc索引部分用布尔条件检索

3、query函数布尔条件检索

如:

1
df.query('staff_salary>10000 & staff_age<40') #通过函数检索staff_age小于40且staff_salary>10000的数据

query函数布尔条件检索

至此,本文介绍了pandas常用的数据访问操作通过head()、tail()、sample()、describe()查看数据,通过[]、loc\iloc、at\iat、及布尔条件检索数据。通过灵活运用pandas的各种数据访问方法可以很方便的根据需要查看和检索数据。

数据集及源代码见:https://github.com/xiejava1018/pandastest.git


作者博客:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

pandas数据处理之数据转换(映射map、替换replace、重命名rename)

发表于 2022-02-04 | 更新于: 2025-08-10 | 分类于 技术 , 开发 | | 阅读次数:
字数统计: 1.6k | 阅读时长 ≈ 6

我们在数据处理的过程中经常碰到需要对数据进行转换的工作,比如将原来数据里的字典值根据字典转义成有意义的说明,将某些数据转换成其他的数据,将空值转换成其他值,将数据字段名进行重命名等。pandas作为数据处理分析的利器当然为上述的这些数据转换提供了便捷的方法。我们可以利用pandas提供的映射、替换、重命名等操作方便的进行相应的数据转换操作。

本文通过实例重点介绍pandas常用的数据转换工具映射map()、替换replace()、重命名rename()

映射:map()函数 对数据集Serice中的元素根据映射关系进行映射(作用于Serice或DataFrame对象的一列)
替换:replace()函数 替换元素 (作用于DataFrame)
重命名:rename()函数 替换索引 (作用于index或columns)

一、映射 map()

在平时数据处理的过程中常常会碰到,某个字段(数据列)是数字表示的要根据映射表转换成有意思的字符。如性别在数据集里存的是1和2分别表示“男”和“女”,如何将数据集中“性别”列的1和2替换成“男”和“女”如何做?绝对不能用for循环一个个去替换。pandas也好、Numpy也好,都是针对数据集处理的,我们应该抛弃以前针对单个数据处理的思维去拥抱针对数据集来编程。使用pandas的map()方法,最少仅需一行代码就可以解决。
map() 函数是做用于 Series 或 DataFrame 对象的一列,它接收一个函数或表示映射关系的字典做为参数,它的基本语法格式以下:

1
Series.map(arg,na_action=None)

函数中的参数说明以下:

  • arg:接收 function、dict 或 Series,表示映射关系;
  • na_action:类似R中的na.action,取值为None或ingore,用于控制遇到缺失值的处理方式,设置为ingore时串行运算过程中将忽略Nan值原样返回。

下面通过实例来说明pandas的map()的使用,演示的student数据集如下:

1
2
3
4
import numpy as np
import pandas as pd
df = pd.read_excel('D:\\Python\\study\\pythontest\\pandastest\\数据集\\student.xlsx')
df

student数据集

1、通过数据字典映射

map()方法接受数据字典参数,通过数据字典将数据进行映射。如我们需要将“性别”列的1和2替换成“男”和“女”,定义一个数据字典{1:’男’,2:’女’},将1映射成“男”,将2映射成“女”。

1
2
3
gender_map={1:'男',2:'女'}
df['性别']=df['性别'].map(gender_map)
df

数据字典映射
可以看到通过map()将需要转换的列的值进行的转换,具体的转换过程如下图所示:
map转换过程

2、lambda函数映射

map()方法还接受lambda函数的方式进行值的映射,如我们现在要把数学分数为95分以上的映射数学等级为“优秀”,95及以下的映射为“良好”。可以通过lambda函数进行映射。

1
2
df['数学等级']=df['5-数学'].map(lambda x:'优秀' if x>95 else '良好')
df

lambda函数映射

3、通用函数映射

map()方法可以接收自定义通用的函数进行值的映射,如我们现在要把语文分数为95以上的映射为语文等级为“优秀”,95及以下的映射为“良好”,也可以通过自定义函数来实现映射。
先定义一个函数score(x)用于接收需要映射的值。

1
2
3
4
5
6
7
8
def score(x):
score_class='良好'
if x>95:
score_class='优秀'
return score_class

df['语文等级']=df['4-语文'].map(score)
df

函数映射

二、替换 replace()

如果要对全DataFrame数据集中的数据进行某种替换,map()可能需要对数据集中的每个列都进行map()操作才可以,但是通过pandas的替换方法replace可以一次性替换掉DataFrame中所有的数据。如:我们现在要将数据集中所有的“良好”替换成“良”,所有的“优秀”替换成“优”
可以直接通过 df.replace(['优秀','良好'],['优','良']) 一句代码搞定。
替换

以前文章中介绍了处理缺失值用fillna的方式来填充缺失值,用replace则提供了一种更加简单、灵活的处理缺失值或异常值的方式。
如在数据集中有一个数据列“是否接种”,这里的值有“已”、“是”、“否”、NaN,实际是在收集统计表格的时候大家填的数据不一致,不标准。现在需要将“已”的全部改成“是”,NaN没有填的改成“否”

1
df.replace(['已',np.nan],['是','否'])

填充缺失值

三、重命名 rename()

在数据处理的过程有时候需要对列索引进行重命名,一个典型的例子就是对于数据的检索或其他操作df[column]对于任意列名均有效,但是df.column只在列名是有效的Python变量名时才有效。
我们在检索英语大于95分的数据时可以用df[df['6-英语']>95]
英语大于95分的数据

但是用df.query('6-英语 >95') 就会报列名没有定义的错,因为’6-英语’列名不是有效的Python变量名。
报列名没有定义的错

这时候就需要将列名重命名为有效的Python变量名,有效的Python变量名应该是只能_,数字,字母组成,不可以是空格或者特殊字符(!@#$%^&*~),不能是数字开头,不能有中文。我们将“6-英语”的列名重命名为“english”。注意带上inplace=True参数用于更新作用于本数据集,而不是返回一个新的数据集。

1
2
df.rename(columns={'6-英语':'english'},inplace=True)
df.query('english > 95')

重命名
可以看到“6-英语”列名改成了“english”,并且df.query(‘english > 95’)不报错,可以正常检索出数据了。
更多的,如果要重命名多个列,可以传入一个需要重命名的多个字典值,进行多个列的重命名。

1
df[['1-学号','2-姓名','3-年龄']].rename(columns={'1-学号':'ID','2-姓名':'name','3-年龄':'age'})

多个列重命名

如果需要重命名行索引,可以通过df.rename(index={‘原索引’:’重命名索引’})的方式进行重命名。

至此,本文通过几个实例介绍了pandas常用的数据转换工具映射map()、替换replace()、重命名rename()

数据集及源代码见:https://github.com/xiejava1018/pandastest.git


作者博客:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

pandas数据分析之数据运算(逻辑运算、算术运算、统计运算、自定义运算)

发表于 2022-02-03 | 更新于: 2025-08-10 | 分类于 技术 , 开发 | | 阅读次数:
字数统计: 2k | 阅读时长 ≈ 7

数据分析离不开数据运算,在介绍完pandas的数据加载、排序和排名、数据清洗之后,本文通过实例来介绍pandas的常用数据运算,包括逻辑运算、算术运算、统计运算及自定义运算。

一、逻辑运算

逻辑运算是程序代码中经常用到的一种运算。pandas的逻辑运算与Python基础语法中的逻辑运算存在一些差异。pandas的逻辑运算主要用于条件过滤根据条件逻辑运算得出的结果过滤检索出相应的数据。
我们来看一些例子:
数据集为学生数据集

1
2
3
4
import pandas as pd
import numpy as np
df = pd.read_excel('D:\\Python\\study\\pythontest\\pandastest\\数据集\\student.xlsx')
df

学生数据集
我们要过滤检索出语文成绩大于95分的数据,通过df['4-语文']>95的条件语句,可以得到一个结果为bool值的Series,True表示满足语文成绩>95分的,False表示不满足语文成绩>95的。
在pandas中,将Series与数值进行比较,会得到一个与自身形状相同且全为布尔值的Series,每个位置的布尔值对应该位置的比较结果。
这种进行比较的代码,返回值是布尔值,是一种布尔表达式,也可以被称为逻辑语句,只要代码返回的结果是布尔值,都可以把代码当成逻辑语句。
语文大于95的逻辑运算
根据逻辑语句的布尔值,可以用来对数据进行筛选,按我们的需要从大量数据中过滤出目标数据。如我们要过滤出语文成绩大于95的数据,就可以用上述逻辑语句的布尔值进行筛选。

1
df[df['4-语文']>95]

语文大于95的结果

除了直接的比较,pandas中有很多函数都会返回布尔值,如all(),any(),isna()等对整个DataFrame或Series的判断结果,eq(),ne(),lt(),gt()等比较函数的结果,都是布尔值。
逻辑语句是为逻辑运算服务的,可以直接作为判断条件。在复杂的逻辑关系中,需要使用复合逻辑运算,用逻辑运算符来连接多个逻辑语句,复合逻辑运算包含:逻辑与&、逻辑或|、逻辑非~。

逻辑与&

pandas中用符号 & 表示逻辑与,连接两个逻辑语句,同时为真才为真。在Python基本语法中,使用 and 表示逻辑与,但是Pandas中只能用 & ,不能用and,会报模糊错误。
如我们要检索出一班并且语文成绩大于95的数据。可以用 df[(df['4-语文']>95) & (df['班级']=='一班')]
注意两个条件逻辑语句要分别用()括起来然后再用逻辑运算符进行运算。
逻辑与&

逻辑或|

pandas中用符号 | 表示逻辑或,连接两个逻辑语句,只要其中一个为真就为真。
在Python基本语法中,使用 or 表示逻辑或,但是Pandas中只能用 | ,不能用or。
如我们要检索出语文成绩大于95或英语成绩大于96的数据

1
df[(df['4-语文']>95)|(df['6-英语']>96)]

逻辑或|

逻辑非~

pandas中用符号 ~ 表示逻辑非,对逻辑语句取反。
在Python基本语法中,使用 not 表示逻辑非,但是Pandas中只能用 ~ ,不能用not。
如我们要检索出数据成绩>98并且不是一班的同学

1
df[(df['5-数学']>98) & ~(df['班级']=='一班')]

逻辑非~

当然也可以用

1
df[(df['5-数学']>98) & (df['班级']!='一班')]

逻辑不等于

二、算术运算

pandas最重要的一个功能是,它可以对不同索引的对象进行算术运算也就是(+、-、*、\)。
常见的算术云算是加法+运算,如果相加的对象是标量,则数据对象通过广播机制,每个数据值都+标量。如果相加的对象是数据对象则按索引进行算术运算。
通过一个数据集来看一下

1
2
3
4
import pandas as pd
import numpy as np
data1=pd.DataFrame(np.arange(16).reshape((4,4)),columns=['列1','列2','列3','列4'])
data1

数据运算数据集

1、使用算术运算符

和标量计算,标量运算会在算术运算过程中传播。

1
2
data2=data1+1
data2

加标量
可以看到数据集中每个值都+1了
和索引相同的数据对象运算,对每个数据值进行算术运算

1
2
3
data3=pd.DataFrame(np.arange(16).reshape((4,4)),columns=['列1','列2','列3','列4'])
data4=data2+data3
data4

DataFrame相加

在将对象相加时,如果存在不同的索引就是该索引对的并集。自动的数据对齐操作在不重叠的索引引入NA值。缺失值会在算术运算过程中传播。

1
2
data5=pd.DataFrame(np.ones([3,3]),columns=['列1','列2','列3'])
data5

全为1的数据集

1
2
data6=data4+data5
data6

形状不同的数据集相加

2、使用算数运算函数

算数运算函数包括add、sub、div、mul等对应于算术运算符如下:

方法 说明
add,radd 用于加法(+)的方法
sub,rsub 用于减法(- )的方法
div,rdiv 用于除法(/)的方法
floordiv,rfloordiv 用于底除(//)的方法
mul,rmul 用于乘法(* )的方法
pow,rpow 用于指数(**)的方法

加法:

在对不同索引的对象进行算术运算时,如果希望当一个对象中某个轴标签在另一个对象中找不到时填充一个特殊值比如0,可以通过算术方法进行填充,然后再相加。
加法函数
上面的例子展示了,因为data5的行索引为3和列索引为列4用0填充后再相加所以行索引为3和列索引为列4的值是data4的值+0

减法:

1
data4.sub(1)

sub函数

乘法:

1
data4.mul(2)

mul函数

除法:

div函数

三、统计运算

统计运算就是我们常用的数据集的求和、算平均值、最大值、最小值、绝对值、标准差等统计数据。在pandas中提供了丰富的统计函数可以方便的进行统计运算。

1、describe汇总描述统计

通过np.random.randn(1000,4)生成1000个正态分布的随机数据集看一下describe的汇总描叙统计。
包含了数据个数count、均值mean、标准差std、最小值min、最大值等。

1
2
3
#1000个正态分布的随机数统计信息
data=pd.DataFrame(np.random.randn(1000,4))
data.describe()

describe汇总描述统计

2、统计函数

pandas常用统计函数如下:
常用统计函数

1
data.max()

max函数

可以算出DataFrame中每一列的最大值

如果只需要计算某一列的最大值

1
data[1].max()

计算某一列的最大值

对单个函数进行统计的时候,坐标轴还是按照这些默认为columns(axis=0, default),如果要对index进行统计,则要指明(axis=1) 这里的axis取值与axis=0对应index,axis=1对应columns不同

  • 使用0值表示沿着每一列或行标签\索引值向下执行方法
  • 使用1值表示沿着每一行或者列标签模向执行对应的方法
    axis=1

如果要计算某一行的最大值
用data.loc[0].max(),通过loc[]检索出需要统计的行,再用统计函数进行统计
计算某一行的最大值
累计统计cumsum,计算前n个数的和
计算前n个数的和

四、自定义运算

如果常用的统计运算还不能满足,pandas提供了方法可以进行自定义运算。

apply(func, axis=0)

  • func – 自定义函数 axis=0 – 默认是列(按行标签方向执行方法)
  • axis=1为对行进行运算(按列标签方向执行方法)

如:自定义一个对列求max-min的函数
head()
通过lambda匿名函数

1
data.apply(lambda x: x.max() - x.min()) # lambda为匿名函数,x为自变量,冒号后面为函数表达式

lambda匿名函数

通过自定义函数

1
2
3
#自定义函数
def maxdivmin(x):
return x.max()-x.min()

自定义函数
至此,本文通过实例简单介绍了pandas数据分析的数据运算包括逻辑运算、算术运算、统计运算、自定义运算,也是平时在实际应用中常用的运算。

数据集及源代码见:https://github.com/xiejava1018/pandastest.git


作者博客:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

pandas数据清洗之处理缺失、重复、异常数据

发表于 2022-02-02 | 更新于: 2025-08-10 | 分类于 技术 , 开发 | | 阅读次数:
字数统计: 1.7k | 阅读时长 ≈ 6

在数据分析和建模的过程中,有相当多的时间要用在数据准备上:加载、清理、转换以及重塑。这些工作会占到分析师时间的80%或更多。幸运的是pandas和内置的Python标准库提供了高效、灵活的工具可以帮助我们轻松的做这些事情。

本文重点介绍通过pandas进行数据的清洗。数据处理中的清洗工作主要包括对需要分析的数据集中的缺失值(空值)、重复值、异常值的处理。对于数据清洗一般也是分两个步骤,第一步就是要很方便快速的找到需要处理的数据,如何快速找到数据中的缺失值(空值)、重复数据或异常的数据,第二步是对找到的数据根据自己的实际使用需求进行处理,如删除还是替换成其他的数据。
pandas数据清洗

一、处理缺失值

在许多数据分析工作过程中,由于对数据质量问题,缺失数据是经常发生的。对于数值数据,pandas使用浮点值NaN(Not a Number)表示缺失数据。在pandas中,还采用了R语言中惯用的缺失值表示法NA,它表示不可用not available。在统计应用中,NA数据可能是不存在的数据或虽然存在但是看不到。进行数据清洗对缺失数据进行分析,以判断数据采集的问题或缺失数据导致的偏差。

1、判断缺失值(空值)

在pandas中通过isna()或isnull()方法判断空值,二者等价,用于判断一个series或dataframe各元素值是否为空的bool结果。需注意对空值的界定:即None或numpy.nan才算空值,而空字符串、空列表等则不属于空值;类似地,notna()和notnull()则用于判断是否非空。
看下实例:

1
2
3
4
import pandas as pd
import numpy as np
stud_data=pd.Series(['张三','李四',np.nan,[],'',None,'王五'])
stud_data

通过stud_data.isnull()和stud_data.isna()分别来判断空值
判断空值

类似地,notna()和notnull()则用于判断是否非空
判断是否非空
同样的对于DataFrame中的缺失数据判断也是一样的。
构建DataFrame

1
2
stud_df=pd.DataFrame(stud_data,columns=['student_name'])
stud_df

DataFrame中的缺失数据判断

对于缺失值的处理有两种常用的方式,一是用按一定的策略对空值进行填充,二是对于缺失值干脆进行删除。

2、填充缺失值(空值)

pandas中用户填充缺失值的方法是fillna(),可以按一定的策略对空值进行填充,如常数填充、向前/向后填充等,也可通过inplace参数确定是否本地更改。

1.常量填充

1
stud_df[['student_name']].fillna('某某')

常量填充

可以看到判断为缺失值的地方都填充了”某某”,因为空字符串和空列表都不是缺失值,所以没有填充。

2.向前和向后填充NA

通过fillna(mathod=’ffill’),mathod=’ffill’ 向前填充和 mathod=’bfill’ 向后填充,也就是说用前面的值来填充NA或用后面的值来填充NA
我们来增加一列性别列gender来看一下。

1
2
3
4
stud_gender_data=pd.Series([1,0,np.nan,'女',1,None,'男'])
stud_df['gender']=stud_gender_data
stud_df
stud_df[['gender']].fillna(method='ffill')

向前和向后填充NA

可以看到通过method=’ffill’,将NaN和None前面的值填充端到了NaN和None。
用fillna()进行填充会返回一个填充好的数据集的副本,并没有对原始数据进行操作,如果要修改原始数据可以通过inplace参数确定是否本地更改。
通过inplace参数确定是否本地更改

3、删除缺失值(空值)

如果想删除缺失值,那么使用 dropna() 函数与参数 axis 可以实现。在默认情况下,按照 axis=0 来按行处理,这意味着如果某一行中存在 NaN 值将会删除整行数据。如果在dropna()中传入how='all'将只会删除全为NA或NaN的行。示例如下:
删除缺失值(空值)

二、处理重复值

重复数据也是在实际数据处理过程中碰到比较多的,处理重复数据就是在数据集中找出重复数据然后将其删除保留一个唯一不重复的数据。

1、检测重复值

pandas通过duplicated()方法检测各行是否重复,返回一个行索引的bool结果,可通过keep参数设置保留第一行、最后一行、无保留,例如keep=first意味着在存在重复的多行时,首行被认为是合法的而可以保留。
构造一个DataFrame来看一个实例:

1
2
3
data=pd.DataFrame({'key1':['A','B']*3+['B'],'key2':[1,1,2,3,3,4,4]})
data
data.duplicated()

检测重复值

2、删除重复值

pandas通过drop_duplicates()方法按行检测并删除重复的记录,也可通过keep参数设置保留项。由于该方法默认是按行进行检测,如果存在某个需要需要按列删除,则可以先转置再执行该方法。

1
data.drop_duplicates()

删除重复值
可以看到第7行也就是index为6的重复行被删除了。
当带了keep='last'参数时,保留最后一个重复项,前面的重复项将被丢弃。可以看到保留的是索引为6的,索引为5的重复项被丢弃了。
保留最后一个重复项

三、处理异常值

1、判断异常值

判断异常值的标准依赖具体分析数据,如大于或小于某个基线范围的值。
我们来看一个含有正态分布的DataFrame数据集

1
2
data=pd.DataFrame(np.random.randn(1000,4))
data.describe()

含有正态分布的DataFrame数据集

假设我们认为某列中绝对值大小超过3的是异常值,那么判断异常值就是要找出某列中大小超过3的值。

1
data[np.abs(col)>3]

找出某列中大小超过3的值

要选出全部含有绝对值大小超过3的行,可以在布尔型DataFrame中使用any()方法。

1
data[(np.abs(data)>3).any(1)]

全部含有绝对值大小超过3的行

2、替换异常值

对于异常值,可以直接替换。
如:

1
data[np.abs(data)>3]=np.sign(data)*3

这样就可以将异常值替换为绝对值不大于3的
替换异常值

3、删除异常值

删除异常值,可以用pandas的drop()方法,接受参数在特定轴线执行删除一条或多条记录,可通过axis参数设置是按行删除还是按列删除
如删除第3列,列索引为2的列中绝对值>3的行

1
2
col=data[2]
data.drop(data[np.abs(col)>3].index,inplace=True)

删除异常值

可以看到本来有1000行的,删除了3行,再用data[np.abs(col)>3]验证,已经找不到数据了。

至此,本文通过实例介绍了pandas进行数据清洗包括缺失值、重复值及异常值的处理。数据清洗是数据分析前面的准备工作,数据质量的好坏将直接影响数据分析的结果。


作者博客:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

pandas数据分析之排序和排名(sort和rank)

发表于 2022-01-30 | 更新于: 2025-08-10 | 分类于 技术 , 开发 | | 阅读次数:
字数统计: 2.1k | 阅读时长 ≈ 7

对数据集进行排序和排名的是常用最基础的数据分析手段,pandas提供了方便的排序和排名的方法,通过简单的语句和参数就可以实现常用的排序和排名。

本文以student数据集的DataFrame为例来演示和介绍pandas数据分析之排序和排名(sort和rank)。
数据集内容如下,包括学生的学号、姓名、年龄及语文、数学、英语的成绩:

1
2
3
4
import pandas as pd
import numpy as np
df = pd.read_excel('D:\\Python\\study\\pythontest\\pandastest\\数据集\\student.xlsx')
df

student数据集
数据集及源代码见:https://github.com/xiejava1018/pandastest.git

一、排序

对数据集进行排序是是常用的数据分析需求之一。pandas提供了按 索引标签排序sort_index()和按值排序sort_values()两种排序方法。对于DataFrame,可以根据任意一个轴上的索引标签进行排序。默认顺序排序,也可以设置按倒序排序。

1、按标签排序

1)按行标签索引排序

pandas默认按行标签索引顺序排序

1
2
#按行索引排序
df.sort_index()

按行索引排序
可以通过设置ascending=False参数进行倒序排序

1
2
#按行索引倒序排序
df.sort_index(ascending=False)

按行索引倒序排序

2)按列标签索引排序

通过给 axis 轴参数传递 0 或 1,可以对列标签进行排序。默认情况下,axis=0 表示按行排序;而 axis=1 则表示按列排序。

1
2
#按列索引排序
df.sort_index(axis=1)

按列索引排序
同样可以设置ascending=False参数进行倒序排序

1
2
#按列索引倒序排序
df.sort_index(axis=1,ascending=False)

按列索引倒序排序

2、按值排序

在实际应用中用得最多的应该是根据某一列的值进行排序。在pandas中可以通过sort_value(),在sort_value中可以设定按某个列排序,也可以通过sort_value(by=[]),通过设置by=[‘a’,’b’]列表来指定多个需要排序的列。

1)对单个列的值排序

如在数据集中对语文成绩进行排序。

1
2
#按语文成绩排序
df.sort_values('4-语文')

对语文成绩进行排序

2)对多个列的值进行排序

通过设置by=[‘a’,’b’]列表来指定多个需要排序的列。
如对数据集中的语文和数学进行排序

1
2
#按语文、数学排序
df.sort_values(by=['4-语文','5-数学'])

对数据集中的语文和数学进行排序

3、排序算法

sort_values() 提供了参数kind用来指定排序算法。这里有三种排序算法:

  • mergesort(归并排序)
  • heapsort(堆排序)
  • quicksort(快速排序)

默认为 quicksort(快速排序) ,其中 mergesort归并排序是最稳定的算法。
具体用法如下:

1
2
#按语文、数学用mergesort归并排序算法排序
df.sort_values(by=['4-语文','5-数学'],kind='mergesort')

排序算法

二、排名

排名和排序的区别在于排序一定是有顺序,而排名分先后并列。如在现实生活中相同的分数存在排名并列的情况。
在《使用python进行数据分析》一书中对rank排名的描述为:排名是指对数组从1到有效数据点总数分配名次的操作。Series和DataFrame的rank方法是实现排名的方法,默认情况下,rank是通过“为各组分配一个平均排名”的方式破坏平级关系。这段话讲得是什么鬼?其实就是在存在并列排名的时候采用一定的策略来打破这种关系。
排名中的平级关系打破方法有如下几种:

method 说明
average 默认:在每个组中分配平均排名
min 对整个组使用最小排名
max 对整个组使用最大排名
first 按照值在数据中出现的次序分配排名
dense 类似于method=’min’,但组件排名总是加1,而不是一个组中的相等元素的数量

rank()函数原型:rank(axis=0, method: str = 'average', numeric_only: Union[bool, NoneType] = None, na_option: str = 'keep', ascending: bool = True, pct: bool = False)
这里method取值可以为’average’,’first’,’min’, ‘max’,’dense’,用来打破排名中的平级关系的。
光看这些说明还是比较难理解。下面通过实例来说明:

1、默认average 排名

在数据集中我们只取“学号”、“姓名”、“语文”,然后取“语文”的排名,默认average

1
2
3
4
df_rank=df[['1-学号','2-姓名','4-语文']].copy()
#按语文成绩进行rank的默认排名
df_rank['语文排名']=df_rank['4-语文'].rank(ascending=False)
df_rank.sort_values(by='语文排名')

默认average 排名

这个排名很奇怪,97分排名第一没有问题,居然没有第二名,三个96分排名均为3,还有两个90分排名为9.5。这是什么鬼?
原来这就是默认的“average”规则,成绩相同时,取顺序排名中所有名次之和除以该成绩的个数,如两个90分的名次为最后两名分别为9名和10名,即(9+10)/2=9.5,三个96分的名次分别为2、3、4 那么排名为(2+3+4)/3=9/3=3

2、mothod=’min’的排名

1
2
3
#按语文成绩进行min排名
df_rank['语文排名']=df_rank['4-语文'].rank(method='min',ascending=False)
df_rank.sort_values(by='语文排名')

按语文成绩进行min排名

在这个排名中看到有3个并列为2的排名,但没有排名为3、4的,有两个排名为9的,但没有排名为10的。可以看出当method=“min”时,成绩相同的同学,取在顺序排名中最小的那个排名作为该值的排名,张三、王五、顾十三个同学都是96分排名分别为2、3、4,那么当method为min时,取2、3、4的最小的那个作为成绩为96的整体排名即第2名。因为有了三个2名,接下来就从5名开始,5、6、7、8,到了第9名又有两个同分数的取9、10的最小排名为9,所以有两个9名。

3、mothod=’max’的排名

1
2
3
#按语文成绩进行max排名
df_rank['语文排名']=df_rank['4-语文'].rank(method='max',ascending=False)
df_rank.sort_values(by='语文排名')

按语文成绩进行max排名
与min相反,成绩相同的同学,排名相同取顺序最大的排名,张三、王五、顾十三个同学都是96分排名分别为2、3、4,那么当method为min时,取2、3、4的最小的那个作为成绩为96的整体排名即第2名。当method为max时,取最大的4作为96分的整体排名,同理90分的取10为90分的整体排名。

4、mothod=’first’的排名

1
2
3
#按语文成绩进行first排名
df_rank['语文排名']=df_rank['4-语文'].rank(method='first',ascending=False)
df_rank.sort_values(by='语文排名')

按语文成绩进行first排名

first排名很好理解了,有点先到先得的意思,成绩相同,谁的索引排前,谁的排名就靠前,比如张三、王五、顾十 这三个同学都是96分,按理应该是并列第2,但张三的索引比王五和顾十的都靠前,王五的索引比顾十靠前,所以他们的顺序分别为2、3、4,同理陈一、钱七的分数都是90分,但陈一的索引比钱七靠前所以陈一排名为9、钱七排名第10

5、mothod=’dense’的排名

1
2
3
#按语文成绩进行dense排名
df_rank['语文排名']=df_rank['4-语文'].rank(method='dense',ascending=False)
df_rank.sort_values(by='语文排名')

按语文成绩进行dense排名
“dense”: 是密集的意思,也比较好理解,即相同成绩的同学排名相同,其他依次加1即可。可以看到张三、王五、顾十这三位同学都是96分,并列排名第2,后面的加1,即比他们分数稍低的赵六95分排名第3,后面依次。

6、不同method的排名对比

最后不同method的排名对比:

1
2
3
4
5
6
7
8
9
10
11
#按语文成绩进行rank的默认排名
df_rank['语文排名-average']=df_rank['4-语文'].rank(ascending=False)
#按语文成绩进行min排名
df_rank['语文排名-min']=df_rank['4-语文'].rank(method='min',ascending=False)
#按语文成绩进行max排名
df_rank['语文排名-max']=df_rank['4-语文'].rank(method='max',ascending=False)
#按语文成绩进行first排名
df_rank['语文排名-first']=df_rank['4-语文'].rank(method='first',ascending=False)
#按语文成绩进行dense排名
df_rank['语文排名-dense']=df_rank['4-语文'].rank(method='dense',ascending=False)
df_rank.sort_values(by='4-语文',ascending=False)

按语文成绩进行rank的默认排名

数据集及源代码见:https://github.com/xiejava1018/pandastest.git


作者博客:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

pandas数据结构(Series和DataFrame)

发表于 2022-01-23 | 更新于: 2025-08-10 | 分类于 技术 , 开发 | | 阅读次数:
字数统计: 2.9k | 阅读时长 ≈ 11

简介

无可非议,pandas是Python最强大的数据分析和探索工具之一,因金融数据分析工具而开发,支持类似于SQL语句的模型,可以对数据进行增删改查等操作,支持时间序列分析,也能够灵活的处理缺失的数据。它含有使数据分析工作变得更快更简单的高级数据结构和操作工具。pandas是基于NumPy构建的,让以NumPy为中心的应用变得更加简单。

这里所说的让pandas变得更快更简单的高级数据结构就是Series和DataFrame。要熟练使用pandas,首先得要熟悉它的这两个主要的数据结构:Series和DateFrame。

本文将针对Series和DateFrame,介绍Series和DataFrame数据对象的创建及基于数据对象的基础上对数据进行选择、增加、删除等数据操作。

一、Series

Series是一种类似于一维数组对象,它是由一组的数据值value(各种NumPy数据类型)以及一组与之相关的数据标签index(即索引)组成,其中标签与数据值之间是一一对应的关系。

1
2
3
import pandas as pd
obj = pd.Series(['陈一','周二','张三','李四','王五','赵六','钱七','孙八','何九','顾十'])
obj

结果:

1
2
3
4
5
6
7
8
9
10
11
0    陈一
1 周二
2 张三
3 李四
4 王五
5 赵六
6 钱七
7 孙八
8 何九
9 顾十
dtype: object

Series的字符串表现形式为:索引在左边,值在右边。由于没有为数据指定索引,于是会自动创建一个0到N-1(N为数据的长度)的整数型索引。
Serires数据结构

可以通过Series的values和index属性获取其数组表示形式和索引对象。
通过Series的values和index属性获取其数组表示形式和索引对象

可以将Series看成一个定长的有序字典,因为它是索引值到数据值的一个映射。

1、Series对象创建

pandas 使用 Series() 函数来创建 Series 对象,通过这个对象可以调用相应的方法和属性,从而达到处理数据的目的:

1
2
import pandas as pd
obj=pd.Series( data, index, dtype, copy)

参数说明如下:

参数名称 描述
data 输入的数据,可以是列表、常量、ndarray 数组等。
index 索引值必须是惟一的,如果没有传递索引,则默认为 np.arrange(n)。
dtype dtype表示数据类型,如果没有提供,则会自动判断得出。
copy 表示对 data 进行拷贝,默认为 False。

data可以是列表、常量、ndarray数组等,如果数据被存放在一个Python字典dict中,也可以直接通过这个dict来创建Series,如果没有传入索引时会按照字典的键来构造索引;反之,当传递了索引时需要将索引标签与字典中的值一一对应。
前面的列子是通过列表来创建的Series,接下来看下通过ndarray和dic来创建Series。

通过ndarray创建Series

1
2
3
4
5
6
#ndarray创建Series
import pandas as pd
import numpy as np
data=np.array(['陈一','周二','张三','李四','王五','赵六','钱七','孙八','何九','顾十'])
obj= pd.Series(data)
print(obj)

结果:

1
2
3
4
5
6
7
8
9
10
11
0    陈一
1 周二
2 张三
3 李四
4 王五
5 赵六
6 钱七
7 孙八
8 何九
9 顾十
dtype: object

通过dict创建Series

#通过dict创建Series,没有设置indx

1
2
3
4
import pandas as pd
data = {'1' :'张三', '2' :'李四', '3' : '王五'}
obj=pd.Series(data)
print(obj)

结果:

1
2
3
4
1    张三
2 李四
3 王五
dtype: object

当传递的索引值无法找到与其对应的值时,使用 NaN(非数字)填充。

1
2
3
4
5
6
#通过dict创建Series,设置indx
import pandas as pd
data = {'1' :'张三', '2' :'李四', '3' : '王五'}
obj=pd.Series(data,index=['1','2','4'])
#索引4没有在dict的对应的key,所以使用NaN(非数字)填充
print(obj)

结果:

1
2
3
4
1     张三
2 李四
4 NaN
dtype: object

2、Series操作

Series数据访问

Series提供了多种数据访问的方式,可以通过位置下标及索引来访问数据,可以访问单个数据也可以访问多个数据。

通过位置下标及索引来访问数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import pandas as pd
import numpy as np
data=np.array(['陈一','周二','张三','李四','王五','赵六'])
obj= pd.Series(data,index=['一','二','三','四','五','六'])
print('obj的Series数据')
print(obj)
print('\n')
#位置下标访问
print('位置下标访问:obj[0]')
print(obj[0])
print('\n')
#切片访问
print('位置切片访问多个元素值:obj[1:3]')
print(obj[1:3])
print('\n')
#索引访问
print('索引访问:obj[obj.index==\'三\']')
print(obj[obj.index=='三'])
print('\n')
#索引访问
print('索引访问:obj[\'一\']')
print(obj['一'])
print('\n')
#索引列表访问
print('索引列表访问多个元素值:obj[[\'二\',\'三\']]')
print(obj[['二','三']])
print('\n')

结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
obj的Series数据
一 陈一
二 周二
三 张三
四 李四
五 王五
六 赵六
dtype: object

位置下标访问:obj[0]
陈一

位置切片访问多个元素值:obj[1:3]
二 周二
三 张三
dtype: object

索引访问:obj[obj.index=='三']
三 张三
dtype: object

索引访问:obj['一']
陈一

索引列表访问多个元素值:obj[['二','三']]
二 周二
三 张三
dtype: object

head()&tail()查看数据

如果想要查看 Series 的某一部分数据,可以使用 head() 或者 tail() 方法。其中 head() 返回前 n 行数据,默认显示前 5 行数据。

1
2
3
4
5
6
7
8
9
10
11
12
import pandas as pd
import numpy as np
data=np.array(['陈一','周二','张三','李四','王五','赵六'])
obj= pd.Series(data,index=['一','二','三','四','五','六'])
#输出前三行数据
print('输出前三行数据')
print(obj.head(3))
print('\n')
#输出后两行数据
print('输出后两行数据')
print(obj.tail(2))
print('\n')

结果:

1
2
3
4
5
6
7
8
9
10
输出前三行数据
一 陈一
二 周二
三 张三
dtype: object

输出后两行数据
五 王五
六 赵六
dtype: object

Series数据增加

1.直接通过索引增加

1
2
3
4
5
6
7
8
9
10
11
12
#通过索引增加数据
obj['十一']='肖十一'
print(obj)

一 陈一
二 周二
三 张三
四 李四
五 王五
六 赵六
十一 肖十一
dtype: object

2.通过append()增加

1
2
3
4
#通过append()增加多个数据
obj2=pd.Series(['郭芙蓉','杨过'],index=['十二','十三'])
obj=obj.append(obj2)
print(obj)

结果:

1
2
3
4
5
6
7
8
9
10
一      陈一
二 周二
三 张三
四 李四
五 王五
六 赵六
十一 肖十一
十二 郭芙蓉
十三 杨过
dtype: object

Series数据修改

Series数据可以通过制定索引直接修改
如:修改索引为十一的数据,直接obj[‘十一’]=’肖XX’,就可以进行修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#修改Series数据
obj['十一']='肖XX'
print(obj)

一 陈一
二 周二
三 张三
四 李四
五 王五
六 赵六
十一 肖XX
十二 郭芙蓉
十三 杨过
dtype: object

Series数据删除

通过drop()删除,注意如果没有带inplace=True,会返回一个新的Series对象。如果要修改本对象,注意要带上inplace=True。

1.删除单个数据

1
2
3
4
5
6
7
8
9
10
11
12
obj.drop('十一',inplace=True)
print(obj)

一 陈一
二 周二
三 张三
四 李四
五 王五
六 赵六
十二 郭芙蓉
十三 杨过
dtype: object

2.删除多个数据

参数为索引列表,即可以删除索引为列表中的数据

1
2
3
4
5
6
7
8
9
10
obj.drop(['十二','十三'],inplace=True)
print(obj)

一 陈一
二 周二
三 张三
四 李四
五 王五
六 赵六
dtype: object

二、DataFrame

DataFrame 是 Pandas 的重要数据结构之一,也是在使用 Pandas 进行数据分析过程中最常用的结构之一。DataFrame 一个表格型的数据结构,既有行标签(index),又有列标签(columns),它也被称异构数据表,所谓异构,指的是表格中每列的数据类型可以不同,比如可以是字符串、整型或者浮点型等。DataFrame 的每一行数据都可以看成一个 Series 结构,只不过,DataFrame 为这些行中每个数据值增加了一个列标签。因此 DataFrame 其实是从 Series 的基础上演变而来。可以把DataFrame看做是关系型数据库里或Excel里的一张表格来理解。
DataFrame数据结构
DataFrame 数据结构的特点:
DataFrame 每一列的标签值允许使用不同的数据类型;
DataFrame 是表格型的数据结构,具有行和列;
DataFrame 中的每个数据值都可以被修改。
DataFrame 结构的行数、列数允许增加或者删除;
DataFrame 有两个方向的标签轴,分别是行标签和列标签;
DataFrame 可以对行和列执行算术运算。

1、DataFrame对象的创建

1
2
import pandas as pd
df=pd.DataFrame( data, index, columns, dtype, copy)

参数说明:

参数名称 说明
data 输入的数据,可以是 ndarray,series,list,dict,标量以及一个 DataFrame。
index 行标签,如果没有传递 index 值,则默认行标签是 np.arange(n),n 代表 data 的元素个数。
columns 列标签,如果没有传递 columns 值,则默认列标签是 np.arange(n)。
dtype dtype表示每一列的数据类型。
copy 默认为 False,表示复制数据 data。

Pandas 提供了多种创建 DataFrame 对象的方式可以看data的参数说明,包括列表、ndarray、series、dict等。
平时在数据分析过程中用得最多的应该是从其他数据源文件如cvs、excel、数据库、WEBAPI等方式加载数据到DataFrame中。
如:从Excel中加载数据。更多的数据加载方式见:http://xiejava.ishareread.com/posts/4864590d/

1
2
3
import pandas as pd
df = pd.read_excel('D:\\Python\\study\\pythontest\\pandastest\\数据集\\staff.xlsx')
df

staff数据集

2、DataFrame数据操作

DataFrame 可以使用行索引(index )来选取 DataFrame 中的数据并进行操作。也可以使用列索(columns )引来完成数据的选取、添加和删除操作。

1) 行索引操作DataFrame

选取数据

行标签选取数据

1
2
#选取行标签为2的行
df.loc[[2]]

选取行标签为2的行
注意:如果是df.loc[2],同样是选择行标签为2的行,但现实效果为
选取行标签为2的行
因为df.loc[2]返回是Series对象,而df.loc[[2]]返回的是DataFrame对象

1
2
type(df.iloc[2])
pandas.core.series.Series
1
2
type(df.loc[[2]])
pandas.core.frame.DataFrame

切片选取数据

1
2
#切片选取数据(左闭右开)
df[2:4]

切片选取数据

增加行

添加数据行,使用 append() 函数,可以将新的数据行添加到 DataFrame 中,该函数会在行末追加数据行。

1
2
3
df_1 = pd.DataFrame([[11,'肖十一','30','女','7000','1'],[12,'郭芙蓉','30','女','7400','1']],index=[11,12],columns = ['staff_id','staff_name','staff_age','staff_gender','staff_salary','staff_depatment_id'])
df=df.append(df_1)
df

 添加数据行

注意新增加的DataFrame如果没有指定行索引,将会默认从0开始,添加数据行后将会有行重复的行索引。如没有指定index=[11,12]

1
2
3
df_1 = pd.DataFrame([[11,'肖十一','30','女','7000','1'],[12,'郭芙蓉','30','女','7400','1']],columns = ['staff_id','staff_name','staff_age','staff_gender','staff_salary','staff_depatment_id'])
df=df.append(df_1)
df

添加数据行有重复行索引

删除行

可以使用行索引标签,从 DataFrame 中删除某一行数据。如果索引标签存在重复,那么它们将被一起删除

1
2
df=df.drop(0)
df

可以看到到行索引为0的两条记录被一起删除了。
删除

2) 列索引操作DataFrame

列索引选取数据列

通过指定列索引来选取数据列,如选择只显示staff_id,staff_name,staff_gender三列

1
2
df2=df[['staff_id','staff_name','staff_gender']]
df2

列索引选取数据列

列索引添加数据列

1
2
3
4
df3=df['staff_salary']+500
#在df的基础上增加append_cloume列,新增的append_cloume列为df['staff_salary']+500,即薪水加了500的列
df['append_cloume']=df3
df

列索引添加数据列

列索引删除数据列

通过del 来删除指定的数据列,如删除staff_depatment_id列

1
2
del df['staff_depatment_id']
df

列索引删除数据列

本文介绍了pandas的两大核心数据结构Series和DataFrame,分别介绍了Series和DataFrame数据对象的创建及基于数据对象的基础上对数据进行选择、增加、删除等数据操作,可以加深对Series和DataFrame的理解,并可以将创建,增、删、改、查等应用于实际的数据处理应用中。


作者博客:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

<1…151617…21>
XieJava

XieJava

208 日志
11 分类
27 标签
RSS
GitHub
友情链接
  • 爱分享读书
  • CSDN
  • 豆瓣
© 2025 XieJava | Site words total count: 426.6k

主题 — NexT.Muse
0%