Pandas基础笔记
Basic knowledge of Pandas
pandas库是以numpy库为基础建成的,是python数据分析的核心库。也正因如此,pandas内的数据结构与numpy的数组有许多相似的地方。
以下的代码示例均是在引入numpy和pandas库的基础上,不要忘记!
Pandas库数据结构简介
Series对象
Series对象用来存放一维数据,由两个相互关联的数组组成。index数组存放索引(令人惊喜的是,索引可以有重复),values数组存放值。其实index对象使得操作Series和DataFrame十分方便(后面会单独拿出来一节将index对象)
声明Series对象
//使用序列创建Series对象
s = pd.Series([1, 2, 3])
s = pd.Series((1, 2, 3))
s = pd.Series(range(0, 6)) //别忘记range也是一种序列对象
s = pd.Series(np.arange(0, 6))
//使用字典创建Series对象
dict = {'red': 2000, 'blue': 1000, 'orange': 5000}
s = pd.Series(dict)
//单从效果上来看是直接构造了自定义索引的index对象,该Series对象可以当做字典使用
//使用其他Series对象构造Series对象
s0 = pd.Series(range(6))
s1 = pd.Series(s0)
//值得注意的是!以此种方式构造的Series并不是副本而是元Series对象的引用!改变原对象会对新对象产生影响
//构造时添加索引(在后面Index对象部分会细讲)
s = pd.Series(np.arange(5), index=['one', 'two', 'three', 'four', 'five'])
'''
得到的Series对象s为
one 0
two 1
three 2
four 3
five 4
dtype: int32
'''
//可以通过以下方式查看索引与值数组
s.values
s.index
操作Series对象
获取Series内部对象
像numpy中操作数组一样操作Series对象
a = pd.Series([1, 2, 3, 4, 5])
//索引与切片
a[1]
a[-1]
a[0:2]
a[0:5:2]
a[5:0:-1]
//筛选
a[a>3] //返回一个Series对象,内部元素为大于3的值. 这个中括号内的a代指每一个元素!
//取对应标签元素
b = pd.Series([1, 2, 3, 4, 5],
index=['one', 'two', 'three', 'four', 'five'])
b[['one', 'four']] //取出索引为'one'和'four'的元素.
Series对象的可变性
// Series对象的Values数组是可变的, 自由但是安全性需要注意
a = pd.Series([1, 2, 3])
a[0] = 3
//你甚至可以这样改变index, 但是values无法被更改, 虽然可以逐个更改
a.index = ['one', 'two', 'three']
Series对象的查重, 包含关系的判断
我们已经领略了Series对象的高度自由, 不过这还不算什么, 好戏在后头呢.
Series对象允许values数组内部元素重复, 那有没有什么方法能实现快速查找重复元素并计数呢?
s = pd.Series([1, 0, 2, 1, 2, 3],
index=['white', 'white', 'blue', 'green',' green','yellow'])
s.unique() //返回array([1, 0, 2, 3], dtype=int64), 返回一个包含s中不重复元素的数组
s.value_counts() //统计重复元素个数
//返回值为:
//2 2
//1 2
//3 1
//0 1
//有的同学可能想问, 有没有index_count呢? 联想是好的, 不过确实没有, 还是自己写一个吧! = W =
Series同时竟还也允许index数组内部元素重复! 也就是允许一对多!
a = pd.Series([1, 2, 3], index=['blue', 'blue', 'red']) //多强啊!
'''
blue 1
blue 2
red 3
dtype: int64
'''
包含关系的判断
isin方法可以实现这个功能, 不过它的设计可能有点反人类. (额, 尤其是学完java的同学, 学python尤其是它的开源库简直煎熬好吗? 就指命名上)
s.isin([0, 3]) //判断[0, 3]是否包含在数据结构中
//值得注意的是: isin接收序列为参数, 它的含义是(以这个为例)0与3, 而不是0-3的元素!
'''返回一个布尔数组
white False
white True
blue False
green False
green False
yellow True
dtype: bool
'''
Series对象的基本算术运算
就像在前面提到过的,Pandas库是建立在Numpy库基础上的,对Numpy数组的许多运算可以直接在Pandas库都为对象中使用,下面的代码示例会提到这一点
// 以下运算均为元素级运算(即对Series内的每一个元素进行运算,在numpy中曾提到过)
a = pd.Series([1, 2, 3])
b = pd.Series([4, 5, 6])
a + b //对应元素相加,如果两Series长度不相同,多出的一位由Nan代替(not a number)
a - b
a * b
a / b
a // b
a % b
a ** b
// 以下为基本函数操作(过于基础,和算术运算符放在一起)
//Series对象可以被numpy中的数学函数实现元素级运算或聚合运算
np.log(a)
np.mean(a)
//几乎所有函数都可以,这里不列举太多(to name but a few)
DataFrame对象
DataFame对象用来存储多维数据, 其设计目的就是将Series对象拓展至多维 (这在暗示DataFrame有很多特性与Series相似), 下图为基本示例
DataFrame对象可以理解为一个由Series组成的字典, column index为字典的key (当然, 这只是一种理解, 形式上很相似)
创建DataFrame对象
刚才说过了, DataFrame可以理解为Series的字典, 那么就用字典来初始化吧!
dict = {'color': ['blue', 'green', 'yellow', 'red', 'white'],
'object': ['ball', 'pen', 'pencil', 'paper', 'mug'],
'price': [1.2, 1.0, 0.6, 0.9, 1.7]}
//你甚至可以通过嵌套字典来构造DataFrame对象, 像这样通过嵌套结构来构造时, 不够的元素会被nan填充
frame = pd.DataFrame(dict, index=['one', 'two', 'three', 'four', 'five'])
'''
color object price
one blue ball 1.2
two green pen 1.0
three yellow pencil 0.6
four red paper 0.9
five white mug 1.7
'''
//我们可以选取特定列进行构造
//通过columns属性指定相关列
frame2 = pd.DataFrame(dict, columns=['color', 'price'],
index=['one', 'two', 'three', 'four', 'five'])
'''
color price
one blue 1.2
two green 1.0
three yellow 0.6
four red 0.9
five white 1.7
'''
//可以通过index, values, columns属性来查看相关信息
通过多维序列初始化 (通常使用arange和reshape)
frame3 = pd.DataFrame(np.arange(16).reshape((4, 4)), index = ['red', 'blue', 'yellow', 'white'],
columns=['ball', 'pen', 'pencil', 'paper'])
操作DataFrame对象
选取DataFrame元素
frame = pd.DataFrame(np.arange(16).reshape((4, 4)),
index=['red', 'blue',' yellow', 'white'],
columns=['ball', 'pen', 'pencil', 'paper'])
'''
ball pen pencil paper
red 0 1 2 3
blue 4 5 6 7
yellow 8 9 10 11
white 12 13 14 15
'''
//对列的选取, 返回Series对象
frame['ball']
frame.ball //像查看属性一样查看列
//你只要将DataFrame类比为Series的字典就很好理解
//对行的选取(也就是index), 返回Series对象
frame.loc('red')
frame.loc(['red', 'blue']) //选取多个行
//选取DataFrame的部分
frame[1:3] //相当于选取0-1行, 0-3列
'''
ball pen pencil paper
blue 4 5 6 7
yellow 8 9 10 11
'''
//选取DataFrame的单个元素, 像操作多维数组一样
frame['pen']['red'] //注意是先选列后选行!
DataFrame对象的修改
-
为了增加可读性, 可以为index和columns属性指定名称
frame.index.name = 'color' frame.columns.name = 'item' ''' item ball pen pencil paper color red 0 1 2 3 blue 4 5 6 7 yellow 8 9 10 11 white 12 13 14 15 '''
-
添加列
frame['new'] = 12 //frame会产生新的一列, 其所有元素均为12 frame['new'] = [1, 2, 3, 4] //也可以借助序列对象, 例如range, np,arange并通过list转化为列表
-
添加行 (与列几乎一样)
frame.loc('new') = 12 //frame会产生新的一行, 其所有元素均为12 frame.loc('new') = [1, 2, 3, 4] //与列同理
-
删除
del frame['new'] //是在原对象上进行修改, 删除new列 //其实del几乎能删除一切你想删掉的东西(指对象), 无法删除函数调用(即使返回对象) //无法删除行的原因就是上一句话, loc方法是一个函数!
DataFrame对象的筛选
//与Numpy中数组, Pandas中的Series一样
frame[frame>0]
//会返回一个布尔数组
判断元素所属关系
frame.isin([0, 3]) //与Series一样
Index对象基础
像Series对象和DataFrame对象在数据分析方面的绝大多数优秀特性都取决于完全整合到这些数据结构中的Index对象
Pandas中的Index对象是不可变的
以下的代码对Series和DataFrame均有效
- 查看index索引
ser = pd.Series([1, 2, 3], index=['one', 'two', 'three'])
//查看标签的最值(字符串由字典顺序)
ser.idmax() //index索引最大值
ser.idmin() //index索引最小值
//查看数据结构是否有重复索引, 通过查看index的is_unique属性
ser.index.is_unique
-
更换索引
通过reindex方法可以更换Series对象的索引, 生成一个新对象.ser.reindex(['1', '2', '3']) //你甚至可以在这个过程中实现删除与添加, 多添加即为增加(nan), 减少即为删除 ----不要忘记是返回新对象
reindex的自动编制索引功能
ser = pd.Series([1, 5, 6, 3], index=[0, 3, 5, 6]) ''' 0 1 3 5 5 6 6 3 ''' //索引列并不是连续的, 可以通过给reindex传参实现智能调整(ffill, bfill) ser.reindex(range(6), method='ffill') ''' 0 1 1 1 2 1 3 5 4 5 5 6 ''' ser.reindex(range(6), method='bfill') ''' 0 1 1 5 2 5 3 5 4 6 5 6 ''' //ffill与bfill的区别在于, ffill将缺失的部分向前取等 //bfill则是向后 (front与back) //对于DataFrame甚至可以更换行与列(你甚至可以同时更换)
-
删除
drop方法返回不含某几行或某几列的新对象
//对于Series ser = pd.Series(np.arange(2.), index=['red', 'blue']) ser.drop('yellow') //删除标签为yellow的这一行 ser.drop(['yellow', 'white']) //对于DataFrame frame = pd.DataFrame(np.arange(16).reshape((4, 4)), index=['red', 'blue', 'yellow', 'white'], columns=['ball', 'pen', 'pencil',' paper']) frame.drop(['blue','yellow']) //删除多行 frame.drop(['pen', 'pencil', axis=1]) //沿着1轴删除多列, axis=1轴即是沿着列
-
算数与数据对齐
这是体现pandas中数据结构灵活的特点的一个地方, Series和DataFrame之间的运算是将数据结构的索引对齐后进行元素级运算. 如果双方标签的集合不同, 取两者并集并在对应位置上放置nan(非常好理解)
-
数据结构之间的运算
基本算数运算方法
add, sub, div, mul
其实它们就是+ - * \ (其实其他的例如 % // 也都也可以参与运算)
DataFrame与Series之间的运算
由于我们可以将DataFrame视作Series的字典, 所以就很显然.
运算的前提是让Series对象的索引和DataFrame对象的列名保持一致(广播机制)
frame = pd.DataFrame(np.arange(16).reshape((4, 4)),
index=['red', 'blue', 'yellow', 'white'],
columns=['ball', 'pen', 'pencil', 'paper'])
'''
ball pen pencil paper
red 0 1 2 3
blue 4 5 6 7
yellow 8 9 10 11
white 12 13 14 15
'''
ser = pa.Series(np.arange(4), index=['ball','pen', 'pencil', 'paper'])
frame + ser
'''
ball pen pencil paper
red 0 2 4 6
blue 4 6 8 10
yellow 8 10 12 14
white 12 14 16 18
'''
//其实就是横着加
//如果有的标签只存在于是个数据结构中, 那么该列会生成nan
函数应用和映射
元素级函数
这类函数被称为通用函数, 对数据结构内的每一个元素进行操作, 其实大多数都是numpy里的内容.
按行或列操作的函数
apply方法(与numpy多维数组中的apply_along_axis几乎一样)可以对元素的每一列执行同一函数(这个函数甚至可以是自定义的)
frame.apply(lambda x: x.max() - x.min()) //默认沿着0轴
frame.apply(lambda x: x.max() - x.min(), axis=1) //沿着1轴
apply函数不仅可以返回标量, 也可以返回Series (要注意的是apply函数是对一行或列执行, 因此返回值总是升1维的, 也就是每行都返回一个标量会香橙Series, 每一行返回一个Series会形成DataFrame)
统计函数
numpy的大多数统计函数对pandas中的对象仍然生效, 没有必要使用apply函数
常用的有mean, sum等
describe方法可以返回多个统计量
排序与排位次
-
对标签或列排序
sort_index方法返回一个顺序不同的新对象(Series, DataFrame通用)
ser.sort_index()
ser.sort_index(ascending=False) //降序
//特殊地, 对于DataFrame, 可以通过axis指定列或index
frame.sort_index(axis=1)
-
对值进行排序
sort_values方法同样返回新对象
ser.sort_values() ser.sort_values(ascending=False) frame.sort_values(by='pen') //指定按照pen列为标准排序 frame.sort_values(by=['pen', 'ball']) // 先看pen列, 若pen列已是顺序, 再看ball列. //同样也可基于更多列
-
排位次操作
位次rank是排序的基石, 也就是说我们可以通过rank方法改变排序的结果
ser.rank() //查看Series的rank值 ser.rank(method='first') //以当前位置定rank, 即当前顺序为标准顺序 ser.rank(ascending=False) //按降序排位次
相关性和协方差
通过corr和cov函数计算两Series对象的相关性与协方差.
调用DataFrame对象的corr或cov方法可计算单个DataFrame对象的相关性与协方差
使用corrwith可计算DataFrame的行或列与Series对象的相关性
NaN数据的处理
-
为元素赋NaN值, 使用np.nan或np.NaN
-
dropna方法或使用过滤(使用notnull作为条件)可实现对nan的过滤
ser.dropna() ser[ser.notnull()] //对于DataFrame, 我们想要去除全部元素为nan的行或列(而不是有nan就删整行) frame.dropna(how='all') //只会删除全为nan的
-
为nan赋值
frame.fillna(0) //为所有nan值赋0值 //可是使用字典来为不同的nan赋不同值 frame.fillna({'ball':1, 'mug':0, 'pen':99}) //不同列的nan会被替换为相应的值
等级索引和分级
- 等级索引是pandas的重要功能, 单条轴可以有多级索引, 可以实现像操作两维结构那样操作多维结构
mser = pd.Series(np.random.rand(8),
index=[['white', 'white', 'white', 'blue', 'blue', 'red', 'red', 'red'], ['up', 'down', 'right', 'up', 'down', 'up', 'down', 'left']])
'''
white up 0.465747
down 0.318715
right 0.576776
blue up 0.975598
down 0.593504
red up 0.491182
down 0.854766
left 0.194188
dtype: float64
'''
//对于DataFrame可以对其行与列均定义登记索引
- 等级索引的基本操作
mser['white']
mser[:,'up']
mser['white':'up']
//unstack方法, 将等级索引Series转化为DataFrame
//stack方法, 将DataFrame转化为等级索引的Series对象
- 新调整顺序
swaplevel方法可以互换两个层级, 以层级的名称为参数!!!!!! 名称是index和columns的name属性!!!!!
sort_index方法可以通过传参数level(同样接收name)来制定对哪个层级将数据排序
-
按层级统计数据
对函数传level参数指定层级名称即可
mframe.sum(level='colors') mframe.sum(level='colors', axis=1)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现