文章目录
- 📚引言
- 📖库的安装以及一些说明
- 📑库的安装
- 📑一些说明
- 📖Series
- 📑创建一个Series
- 🔖从列表创建Series
- 🔖从字典创建Series
- 🔖标量创建Series
- 📑Series的特点与属性
- 🔖Series取值
- 🔖Series调用函数
- 🔖Series间的操作
- 🔖Series的属性
- 📍总结
📚引言
🙋♂️作者简介:生鱼同学,大数据科学与技术专业硕士在读👨🎓,曾获得华为杯数学建模国家二等奖🏆,MathorCup 数学建模竞赛国家二等奖🏅,亚太数学建模国家二等奖🏅。
✍️研究方向:复杂网络科学
🏆兴趣方向:利用python进行数据分析与机器学习,数学建模竞赛经验交流,网络爬虫等。
pandas作为python一个非常强大的数据分析和处理库,可以帮我们进行多种不同的任务,包括但不限于下面这些方面:
- 数据探索
- 数据清洗
- 数据可视化
- …
掌握pandas能够帮助我们有效的提高工作效率,也可以帮我们跟深入的探索数据背后的意义和规律。
从本文开始,我们将会按照pandas说明文档给出的学习路线出发,结合实际操作过程中遇到的问题逐步的掌握pandas这个强大的库。
话不多说,我们开始吧。
📖库的安装以及一些说明
📑库的安装
在开始之前请确保你已经安装了pandas的最新版本,你可以直接利用下面的代码在控制台安装pandas以及numpy:
pip install pandas
pip install numpy
亦或者习惯用Andaconda的小伙伴可以实用conda来安装,代码如下:
conda install pandas
conda install numpy
具体的安装以及环境配置流程不在本文的重点关注范围,后续我将会在后面的内容中发布安装相关的博文,如果需要可以点个关注持续关注我。
📑一些说明
需要说明的是本文的代码环境以及版本:
- python : 3.8.16
- pandas : 1.5.3
- numpy : 1.23.5
最后,本系列将会使用Jupyter Notebook作为示范的编译环境。
注意:在开始使用pandas之前请在代码中导入两个库:
import pandas as pd
import numpyt as np
在本文中,我们主要讨论pandas中最重要的两种数据结构Series以及DataFrame。当然,本文只是对其进行粗浅的介绍,让大家知道它们到底是个什么玩意儿,在后续的更新中,我们将会基于这两个数据结构解锁更多的新姿势玩转pandas。
我们首先来看基础数据结构Series。
📖Series
我们首先来看Pandas的说明文档对Series的解释:
说明文档原文:Series是一个一维标签数组,能够容纳任何数据类型(整数、字符串、浮点数、Python对象等),轴的标签被统称为索引。
从我的理解来看,可以把Series当成一个功能强大的字典,其可以快捷的帮我们进行一些操作并且有一些字典没有的特性。
特别的,Series也是后面要介绍的DataFrame的基本单位。
📑创建一个Series
创建一个Series只需要一句代码,如下:
s = pd.Series(data, index=index)
在这个基础创建函数中接受两个参数:
- data : 用于创建Series的数据,可以是一个字典,一个ndarray(np中的数据结构)或者一个标量(例如:1)
- index : data的标签,按照不同的情况传入参数不同,得到的结果不同
为了更好的演示上面的创建过程,我们来看下面几种情况:
🔖从列表创建Series
从列表创建一个Series当然是允许的,请看下面两个代码示例:
list_01 = [random.randint(0,100) for i in range(5)]
# 当我们没有传入index的时候会自动创建index
pd.Series(list_01)
>>> 0 33
>>> 1 8
>>> 2 80
>>> 3 16
>>> 4 56
>>> dtype: int64
list_01 = [random.randint(0,100) for i in range(5)]
# 注意这里的区别,我们传入了字符类型的index
pd.Series(list_01, index = ['a','b','c','d','e'])
>>> a 98
>>> b 44
>>> c 40
>>> d 78
>>> e 54
>>> dtype: int64
由上述代码我们可知,当我们使用类似利列表的序列创建Series时,如果不传入index,pandas将会帮我们默认生成从0开始的序列作为index。
当然,使用元组,ndarray等结构作为data创建Series的结果将会类似。使用numpy中的ndarray完成上述操作将会更加的简洁,请看下面的示例:
pd.Series(np.random.randn(5))
>>> 0 0.154329
>>> 1 0.369949
>>> 2 0.281314
>>> 3 0.880517
>>> 4 0.123413
>>> dtype: float64
说明文档原文:pandas支持非唯一的索引值。如果一个不支持重复索引值的操作被尝试,届时将引发一个异常。
针对上述这点注意,我们看下面这个例子:
# 在这里的index中我们赋了重复的值
test_s = pd.Series(np.random.randn(5),index = ['a','b','c','d','a'])
test_s['a']
>>> a -0.486072
>>> a 1.693092
>>> dtype: float64
注意:虽然我们使用上述的重复index依然取到了值,但是在使用的过程中应该尽量避免重复的索引,以免有意外的报错发生。
🔖从字典创建Series
从字典创建一个Series的结果更容易被我们预料到,因为字典和Series的机制很相似,都有index对应的value。但是,还有一些其它的情况要说明,请看下面这个代码:
dict_01 = {
'a':1,
'b':2,
'c':3,
'd':4,
}
pd.Series(dict_01)
>>> a 1
>>> b 2
>>> c 3
>>> d 4
>>> dtype: int64
在上述的例子中,字典很顺利的生成了一个Series,但是如果我们传入的index超过了字典key的范围将会怎么样呢?请看下面这段代码:
dict_01 = {
'a':1,
'b':2,
'c':3,
'd':4,
}
# 字典有四个键,但是我们传入了五个index
pd.Series(dict_01, index = ['a','b','c','d','e'])
>>> a 1.0
>>> b 2.0
>>> c 3.0
>>> d 4.0
>>> e NaN
>>> dtype: float64
可以看到,当我们传入的索引超出了字典的范围时并不会触发错误,Series自动的将多出来的索引赋为NaN即不存在。
说明文档原文:NaN(非数字)是pandas中使用的标准缺失数据标记。
🔖标量创建Series
当我们使用标量创建一个Series的时候,如果我们没有预先指定长度,那么它会默认生成一个只有一个数字的Series,如下所示:
pd.Series(5)
>>> 0 5
>>> dtype: int64
如果我们为其指定index那么其生成的Series将会变的不同,即生成定长的标量Series,如下所示:
pd.Series(5,index = ['a','b','c','d','e'])
>>> a 5
>>> b 5
>>> c 5
>>> d 5
>>> e 5
>>> dtype: int64
📑Series的特点与属性
🔖Series取值
Series可以像python内置序列一样让我们根据下标取数或者直接根据我们设定的index进行取数,如下所示:
test_s = pd.Series(range(5),index = ['a','b','c','d','e'])
# 利用数字序列取数
test_s[0]
# 利用index取数
test_s['a']
>>> 5
>>> 5
另外,Series还接受切片的操作,如下所示:
test_s[2:]
>>> c 2
>>> d 3
>>> e 4
>>> dtype: int64
进一步的,我们可以根据上述的索引对其进行赋值是肯定的,所以本文不在这里进行演示。
🔖Series调用函数
Series可以调用大多数NumPy中的函数,并且利用这种特性加上索引取数可以达到很好的过滤元素的效果,下面展示几个非常常用的函数:
test_s = pd.Series(np.random.randn(20))
# 求平均数
print(test_s.mean())
# 求标准差
print(test_s.std())
# 求中位数
print(test_s.median())
# 对Series的value进行排序
test_s.sort_values()
>>> -0.8208612506544736
>>> 0.7848416493146942
>>> -0.7914818370858607
>>> 1 -2.173978
>>> 5 -1.815420
>>> 0 -1.286937
>>> 4 -1.147945
>>> 3 -0.857540
>>> 7 -0.725424
>>> 9 -0.106355
>>> 8 -0.073792
>>> 6 -0.071470
>>> 2 0.050249
>>> dtype: float64
除上述较为常用的函数外,Series可用的方法有很多,如下所示:
print([attr for attr in dir(s) if not attr.startswith('_')])
结果如下:
🔖Series间的操作
Series可以利用常用的运算符进行拼接操作,并且允许NumPy中的函数直接对其进行操作,如下所示:
test_s = pd.Series(range(5),index = ['a','b','c','d','e'])
# 对Series进行自己相加
test_s + test_s
# 对Series进行乘法操作
test_s * 3
# 对Series进行幂次操作
test_s ** 3
# nunpy内置函数对其进行操作
np.exp(test_s)
特别的,Series会自动进行索引对齐,这是非常重要的性质,因为Series能够进行索引对其而使得其更加的灵活。我们看下面这两个例子:
# 创建两个Series
# 注意:在s_2中索引呗打乱了顺序
s_1 = pd.Series(range(5),index=['a','b','c','d','e'])
s_2 = pd.Series(range(5),index=['b','a','d','c','e'])
>>> a 0 b 0
>>> b 1 a 1
>>> c 2 d 2
>>> d 3 c 3
>>> e 4 e 4
>>> Name: s_1, dtype: int64 Name: s_2, dtype: int64
此时,如果我们对上述的两个Series相加,将会得到什么样的结果呢?我们相加试试看:
s_1 + s_2
>>> a 1
>>> b 1
>>> c 5
>>> d 5
>>> e 8
>>> dtype: int64
可以发现,Series自动对其了相等的索引进行相加了。
理解这个特性将会更好的帮我们理解Series强大的灵活性以及其的多样性。
🔖Series的属性
在Series中我们第一眼见到的有两个属性即dtype与name,我们将分别来介绍,首先来看dtype。
当我们调用Series的dtype属性时,就可以得到Series的dtype,如下所示:
s = pd.Series([i/2 for i in range(5)])
s.dtype
>>> dtype('float64')
原文介绍:这通常是一个NumPy的dtype。然而,pandas和第三方库在一些地方扩展了NumPy的类型系统,在这种情况下,dtype将是一个ExtensionDtype。
关于dtype的具体内容,我们将在后续的文章中详细说明,这里先做了解。
其次,name属性也是Series中一个非常重要的属性,当我们定义一个新的Series时,我们可以为其指定name。同时,我们也可以调用Series的name属性直接获取到Series的name。如下所示:
s = pd.Series([i/2 for i in range(5)], name = 'Ecample_2023')
s.name
>>> 'Ecample_2023'
当然,我们可以使用rename()
函数来进行Series的重命名,代码如下:
s = pd.Series([i/2 for i in range(5)], name = 'Example_2023')
print(s.name)
s.rename('motify_Example_2023')
>>> Example_2023
>>>
>>> 0 0.0
>>> 1 0.5
>>> 2 1.0
>>> 3 1.5
>>> 4 2.0
>>> Name: motify_Example_2023, dtype: float64