0
点赞
收藏
分享

微信扫一扫

【Pandas】Pandas基础



需要使用的数据
数据learn_pandas



Pandas基础

  • ​​Pandas基础​​
  • ​​文件的读取和写入​​
  • ​​基本数据结构​​
  • ​​Series​​
  • ​​DataFrame​​
  • ​​基本常用函数​​
  • ​​索引​​
  • ​​分组​​
  • ​​分组模式​​
  • ​​聚合模式​​
  • ​​连接​​
  • ​​缺失数据​​
  • ​​缺失值的统计和删除​​
  • ​​缺失值的填充​​



Pandas基础

使用到的数据如下所示,可以将其保存为不同的文件以供练习


col1,col2,col3,col4,col5
2,a,1.4,apple,2020/1/1
3,b,3.4,banana,2020/1/2
6,c,2.5,orange,2020/1/5
5,d,3.2,lemon,2020/1/7


文件的读取和写入

读取csv、excel和txt文件

# 读取csv文件
csv_data = pd.read_csv("data/my_csv.csv")
print(csv_data)
# 读取excel文件
excel_data = pd.read_excel("data/my_excel.xlsx")
print(excel_data)
# 读取txt文件
table_data = pd.read_table("data/my_table.txt")
print(table_data)

【Pandas】Pandas基础_python

这里有一些常用的公共参数, ​​header=None​​ 表示第一行不作为列名,​​index_col​​表示把某一列或几
列作为索引, ​​usecols​​ 表示读取列的集合,默认读取所有的列, ​​parse_dates​​ 表示需要转化为时间的
列, ​​nrows​​ 表示读取的数据行数。上面这些参数在上述的三个函数里都可以使用。

第一行不做索引

csv_data_no_head = pd.read_csv("data/my_csv.csv", header=None)
print(csv_data_no_head)

【Pandas】Pandas基础_数据挖掘_02

选取单独列作为索引

csv_data_choice_col = pd.read_csv("data/my_csv.csv", index_col=['col1', 'col2'])
print(csv_data_choice_col)

【Pandas】Pandas基础_数据挖掘_03

指定读取的列

csv_data_choice_col_2 = pd.read_csv("data/my_csv.csv", usecols=['col1', 'col2'])
print(csv_data_choice_col_2)

【Pandas】Pandas基础_数据_04

处理时间

csv_data_time = pd.read_csv("data/my_csv.csv", parse_dates=['col5'])
print(csv_data_time)

【Pandas】Pandas基础_python_05

选择读取的行数

csv_data_rows = pd.read_csv("data/my_csv.csv", nrows=3)
print(csv_data_rows)

【Pandas】Pandas基础_数据分析_06

数据的写入

一般在数据写入中,最常用的操作是把 ​​index​​ 设置为​​False​​,特别当索引没有特殊意义的时候,这样
的行为能把索引在保存的时候去除。

df_csv.to_csv('data/my_csv_saved.csv', index=False)
df_excel.to_excel('data/my_excel_saved.xlsx', index=False)

​pandas​​中没有定义​​to_table​​ 函数,但是 ​​to_csv​​可以保存为 txt 文件,并且允许自定义分隔符,
常用制表符 \t 分割:

df_txt.to_csv('data/my_txt_saved.txt', sep='\t', index=False)

​​跳转顶部​​

基本数据结构

​pandas​​ 中具有两种基本的数据存储结构,存储一维​​values​​ 的 ​​Series​​ 和存储二维​​values​​ 的
​DataFrame​​,在这两种结构上定义了很多的属性和方法。

Series

​Series​​ 一般由四个部分组成,分别是序列的值 ​​data​​ 、索引​​index​​ 、存储类型 ​​dtype​​ 、序列的名字
​name​​ 。其中,索引也可以指定它的名字,默认为空。

s = pd.Series(data=[100, 'a', {"name": "Jack"}],
index=pd.Index(["ID", 20, 'third'], name="my_idx"),
dtype='object',
name='my_name')

【Pandas】Pandas基础_数据挖掘_07

注意: object 代表了一种​混合类型​,正如上面的例子中存储了整数、字符串以及 Python 的字典数据结构。

对于这些属性,可以通过 ​​.​​的方式来获取:

# 获取值
print(s.values)
# 获取 索引
print(s.index)
# 获取 数据类型
print(s.dtype)
# 获取列名
print(s.name)
# 获取长度
print(s.shape)

【Pandas】Pandas基础_python_08

​​跳转顶部​​

DataFrame

​DataFrame​​ 在 ​​Series​​ 的基础上增加了​列索引​。

df = pd.DataFrame(data={'col_0': [1, 2, 3], 'col_1': list('abc'),
'col_2': [1.2, 1.3, 1.4]},
index=['row_%d' % i for i in range(3)])

【Pandas】Pandas基础_pandas_09

在 ​​DataFrame​​中可以用​​[col_name]​​与 ​​[col_list]​​ 来取出相应的列与由多个列组成的表,结果分
别为​​Series​​和​​DataFrame​​ :

# 获取第一列,只获取列的时候就是一个Series
print(df['col_2'])
# 获取第一二两列
print(df[['col_1', 'col_2']])

【Pandas】Pandas基础_数据_10

与 ​​Series​​ 类似,在数据框中同样可以取出相应的属性:

# 获取值
print(df.values)
# 获取 索引
print(df.index)
# 获取长度
print(df.shape)
# 返回数据类型
print(df.dtypes)
# 获取列名
print(df.columns)

【Pandas】Pandas基础_数据_11

​​跳转顶部​​

基本常用函数

为了进行举例说明,在接下来的部分和其余章节都将会使用一份​​learn_pandas.csv​​ 的虚拟数据集,
它记录了四所学校学生的体测个人信息。

数据查看

df = pd.read_csv('data/learn_pandas.csv')
# 列名
print('列名\n', df.columns)

【Pandas】Pandas基础_python_12

上述列名依次代表学校、年级、姓名、性别、身高、体重、是否为转系生、体测场次、测试时间、1000
米成绩,本章只需使用其中的前七列。

print("前七列\n", df[df.columns[:7]])

【Pandas】Pandas基础_python_13

汇总函数,​​head​​查看前几行,​​tail​​查看后几行

# 前2行
print('前两行数据\n', df.head(2))
# 后三行
print('前两行数据\n', df.tail(3))

【Pandas】Pandas基础_数据挖掘_14

​info​​, ​​describe​​分别返回表的 信息概况 和表中 数值列对应的主要统计量 :

# 查看信息
print('查看信息\n', df.info())
# describe
print('describe\n', df.describe())

【Pandas】Pandas基础_数据_15

特征统计函数

在 ​​Series​​ 和 ​​DataFrame​​上定义了许多统计函数,最常见的是 ​​sum​​, ​​mean​​, ​​median​​, ​​var​​, ​​std​​,
​max​​, ​​min​​ 。例如,选出身高和体重列进行演示:

df_demo = df[['Height', 'Weight']]
print('平均值\n', df_demo.mean())
print('最大值\n', df_demo.max())

【Pandas】Pandas基础_数据挖掘_16

此外,需要介绍的是 ​​quantile​​, ​​count​​, ​​idxmax​​ 这三个函数,它们分别返回的是分位数(前百分之多少的数据)、非缺失值个数、最大值对应的索引:

print('分位数\n', df_demo.quantile(0.25))
print('非缺失值个数\n', df_demo.count())
print('最大值对应的索引\n', df_demo.idxmax())

【Pandas】Pandas基础_数据挖掘_17

上面这些所有的函数,由于操作后返回的是标量,所以又称为聚合函数,它们有一个公共参数 ​​axis​​,​默认为0代表逐列聚合,如果设置为1则表示逐行聚合​:

print('对行来进行聚合\n', df_demo.mean(axis=1).head())

【Pandas】Pandas基础_python_18

唯一值函数

对序列使用 ​​unique​​和 ​​nunique​​ 可以分别得到其唯一值组成的列表和唯一值的个数:

​​跳转顶部​​

# 唯一值的列表
print("唯一值的列表\n", df['School'].unique())
# 唯一值得个数
print("唯一值的个数\n", df['School'].nunique())

【Pandas】Pandas基础_数据分析_19

​value_counts​​可以得到唯一值和其对应出现的频数:

print('唯一值和其出现的频数\n', df['School'].value_counts())

【Pandas】Pandas基础_数据分析_20

如果想要观察多个列组合的唯一值,可以使用 ​​drop_duplicates​​。其中的关键参数是​​keep​​ ,默认值​​first​​ 表示每个组合保留第一次出现的所在行,​​last​​ 表示保留最后一次出现的所在行, False 表示把所有重复组合所在的行剔除。

df_demo = df[['Gender', 'Transfer', 'Name']]
print('两行重复输出第一次出现的值\n', df_demo.drop_duplicates(['Gender', 'Transfer']))
print('两行重复输出最后一次出现的值\n', df_demo.drop_duplicates(['Gender', 'Transfer'], keep='last'))
print('保留只出现过一次的数据\n', df_demo.drop_duplicates(['Name', 'Gender'], keep=False).head())

【Pandas】Pandas基础_数据挖掘_21

此外, ​​duplicated​​和 ​​drop_duplicates​​的功能类似,但前者返回了是否为唯一值的布尔列表,其​​keep​​ 参数与后者一致。其返回的序列,把重复元素设为 ​​True​​ ,否则为​​False​​ 。 ​​drop_duplicates​​等价于把 ​​duplicated​​为​​True​​的对应行剔除。

print('展示是否为重复行\n', df_demo.duplicated(['Gender', 'Transfer']).head())

【Pandas】Pandas基础_数据挖掘_22

排序函数

排序共有两种方式,其一为值排序,其二为索引排序,对应的函数是 ​​sort_values​​ 和​​sort_index​​ 。为了演示排序函数,下面先利用 ​​set_index​​方法把年级和姓名两列作为索引

df_demo = df[['Grade', 'Name', 'Height', 'Weight']].set_index(['Grade', 'Name'])

【Pandas】Pandas基础_pandas_23

对身高进行排序,默认参数 ​​ascending=True​​为升序:

print('身高升序排序\n', df_demo.sort_values('Height').head())
print('身高降序排序\n', df_demo.sort_values('Height', ascending=False).head())

【Pandas】Pandas基础_数据分析_24

在排序中,经常遇到多列排序的问题,比如在体重相同的情况下,对身高进行排序,并且保持身高降序排列,体重升序排列:

print('身高降序,体重升序\n', df_demo.sort_values(['Weight', 'Height'], ascending=[True, False]).head())

【Pandas】Pandas基础_数据_25

索引排序的用法和值排序完全一致,只不过元素的值在索引中,此时需要指定索引层的名字或者层号,用参数 level 表示。另外,需要注意的是字符串的排列顺序由字母顺序决定。

print('索引排序\n', df_demo.sort_index(level=['Grade', 'Name'], ascending=[True, False]).head())

【Pandas】Pandas基础_数据挖掘_26

索引

表的列索引

列索引是最常见的索引形式,一般通过 [] 来实现。通过 [列名] 可以从 ​​DataFrame​​ 中取出相应的列,返回值为 ​​Series​​ ,例如从表中取出姓名一列:

df = pd.read_csv('data/learn_pandas.csv', usecols=['School', 'Grade', 'Name', 'Gender', 'Weight', 'Transfer'])
print('取出姓名一列\n', df['Name'].head())

【Pandas】Pandas基础_数据分析_27

如果要取出多个列,则可以通过 [列名组成的列表] ,其返回值为一个 ​​DataFrame​​,例如从表中取出性别和姓名两列:

print('取出多列\n', df[['Gender', 'Name']].head())

【Pandas】Pandas基础_python_28

序列的行索引

如果取出单个索引的对应元素,则可以使用 ​​[item]​​,若 ​​Series​​只有单个值对应,则返回这个标量值,如果有多个值对应,则返回一个 ​​Series​​ :

s = pd.Series([1, 2, 3, 4, 5, 6], index=['a', 'b', 'a', 'a', 'a', 'c'])
print('Series单个值对应\n', s['a'])
print('Series多个值对应\n', s[['c', 'b']])

【Pandas】Pandas基础_数据分析_29

loc索引器

前面讲到了对 ​​DataFrame​​的列进行选取,下面要讨论其行的选取。对于表而言,有两种索引器,一种是基于 元素 的​​loc​​ 索引器,另一种是基于 位置 的 iloc 索引器。

​loc​​ 索引器的一般形式是 ​​loc[*, *]​​,其中第一个 * 代表行的选择,第二个 * 代表列的选择,如果省略第二个位置写作​​loc[*]​​,这个 * 是指行的筛选。

df_demo = df.set_index('Name')
print('数据前五行\n', df_demo.head())

【Pandas】Pandas基础_pandas_30

此时,直接取出相应的行或列,如果该元素在索引中重复则结果为 ​​DataFrame​​,否则为 ​​Series​​ :

print('直接取出相应的列(数据重复)\n', df_demo.loc['Qiang Sun'])
print('直接取出相应的列(数据不重复)\n', df_demo.loc['Quan Zhao'])

【Pandas】Pandas基础_数据分析_31

也可以同时选择行和列:

print('同时选择行和列\n', df_demo.loc['Qiang Sun', 'School'])

【Pandas】Pandas基础_数据挖掘_32

此时,取出列表中所有元素值对应的行或列:

print('取出列表中所有元素值对应的行或列\n', df_demo.loc[['Qiang Sun', 'Quan Zhao'], ['School', 'Gender']])

【Pandas】Pandas基础_数据分析_33

​iloc​​ 的使用与 ​​loc​​ 完全类似,只不过是针对位置进行筛选,,函数的返回值必须是前面的四类合法对象中的一个,其输入同样也为 ​​DataFrame​​ 本身。

print('第二行第二列\n', df_demo.iloc[1, 1])
print('前两行前两列\n', df_demo.iloc[[0, 1], [0, 1]])

print('第二到四行,三到四列\n', df_demo.iloc[1: 4, 2:4])

【Pandas】Pandas基础_数据挖掘_34

​​跳转顶部​​

分组

分组模式

分组的一般模式

分组操作在日常生活中使用极其广泛,例如:

  • 依据 性别 分组,统计全国人口 寿命 的 平均值
  • 依据 季节 分组,对每一个季节的 温度 进行 组内标准化
  • 依据 班级 分组,筛选出组内 数学分数 的 平均值超过80分的班级

从上述的几个例子中不难看出,想要实现分组操作,必须明确三个要素:分组依据 、 数据来源 、 操作及其返回结果 。同时从充分性的角度来说,如果明确了这三方面,就能确定一个分组操作,从而分组代码的一般模式即:

df.groupby(分组依据)[数据来源].使用操作

现在返回到学生体测的数据集上,如果想要按照性别统计身高中位数,就可以如下写出:

df = pd.read_csv('data/learn_pandas.csv')
print('按照性别求身高中位数\n', df.groupby('Gender')['Height'].median())

【Pandas】Pandas基础_pandas_35

​​跳转顶部​​

聚合模式

了解一些直接定义在groupby对象的聚合函数,因为它的速度基本都会经过内部的优化,使用功能时应当优先考虑。根据返回标量值的原则,包括如下函数:

max/min/mean/median/count/all/any/idxmax/idxmin/mad/nunique/skew/quantile/sum/std/v
ar/sem/size/prod 。
gb = df.groupby('Gender')['Height']
print('最小值所在的行\n', gb.idxmin())
print('前百分之五的身高\n', gb.quantile(0.95))

gb = df.groupby('Gender')[['Height', 'Weight']]
print('按照列的迭代计算\n', gb.max())

【Pandas】Pandas基础_数据分析_36

​​跳转顶部​​

连接

连接的基本概念

​​跳转顶部​​

把两张相关的表按照某一个或某一组键连接起来是一种常见操作,例如学生期末考试各个科目的成绩表按照 姓名 和 班级 连接成总的成绩表,又例如对企业员工的各类信息表按照 员工ID号 进行连接汇总。由此可以看出,在关系型连接中, 键 是十分重要的,往往用 ​​on​​ 参数表示。

另一个重要的要素是连接的形式。在 ​​pandas​​ 中的关系型连接函数​​merge​​和 ​​join​​中提供了​​how​​ 参数来代表连接形式,分为左连接​​left​​、右连接​​right​​ 、内连接​​inner​​、外连接​​outer​​,它们的区别可以用如下示意图表示:

【Pandas】Pandas基础_数据挖掘_37

从图中可以看到,所谓左连接即以左表的键为准,如果右表中的键于左表存在,那么就添加到左表,否则则处理为缺失值,右连接类似处理。内连接只负责合并两边同时出现的键,而外连接则会在内连接的基础上包含只在左边出现以及只在右边出现的值,因此外连接又叫全连接。

上面这个简单的例子中,同一个表中的键没有出现重复的情况,那么如果出现重复的键应该如何处理?只需把握一个原则,即只要两边同时出现的值,就以笛卡尔积的方式加入,如果单边出现则根据连接形式进行处理。其中,关于笛卡尔积可用如下例子说明:设左表中键 张三 出现两次,右表中的 张三 也出现两次,那么逐个进行匹配,最后产生的表必然包含 2*2 个姓名为 张三 的行。下面是一个对应例子的示意图:

【Pandas】Pandas基础_数据挖掘_38

显然在不同的场合应该使用不同的连接形式。其中左连接和右连接是等价的,由于它们的结果中的键是被一侧的表确定的,因此常常用于有方向性地添加到目标表。内外连接两侧的表,经常是地位类似的(左右表位置的交换不引起结果的变化),想取出键的交集或者并集,具体的操作还需要根据业务的需求来判断。

值连接

在上面示意图中的例子中,两张表根据某一列的值来连接,事实上还可以通过几列值的组合进行连接,这种基于值的连接在 ​​pandas​​ 中可以由​​merge​​ 函数实现,例如第一张图的左连接:

df1 = pd.DataFrame({'Name': ['San Zhang', 'Si Li'], 'Age': [20, 30]})
df2 = pd.DataFrame({'Name': ['Si Li', 'Wu Wang'], 'Gender': ['F', 'M']})
print('merge连接\n', df1.merge(df2, on='Name', how='left'))

【Pandas】Pandas基础_数据_39

在某些时候出现重复元素是麻烦的,例如两位同学来自不同的班级,但是姓名相同,这种时候就要指定on 参数为多个列使得正确连接:

df1 = pd.DataFrame({'Name': ['San Zhang', 'San Zhang'], 'Age': [20, 21], 'Class': ['one', 'two']})
df2 = pd.DataFrame({'Name': ['San Zhang', 'San Zhang'], 'Gender': ['F', 'M'], 'Class': ['two', 'one']})
print('左连接\n', df1.merge(df2, on=['Name', 'Class'], how='left'))

【Pandas】Pandas基础_数据_40

索引连接

所谓索引连接,就是把索引当作键,因此这和值连接本质上没有区别, ​​pandas​​中利用​​join​​ 函数来处理索引连接,它的参数选择要少于 ​​merge​​ ,有​​on​​和 ​​how​​。其中, ​​on​​ 参数指索引名,单层索引时省略参数表示按照当前索引连接。

df1 = pd.DataFrame({'Age': [20, 30]}, index=pd.Series(['San Zhang', 'Si Li'], name='Name'))
df2 = pd.DataFrame({'Gender': ['F', 'M']}, index=pd.Series(['Si Li', 'Wu Wang'], name='Name'))
print('索引连接\n', df1.join(df2, how='left'))

【Pandas】Pandas基础_数据_41

缺失数据

缺失值的统计和删除

缺失信息的统计

缺失数据可以使用 ​​isna​​或 ​​isnull​​(两个函数没有区别)来查看每个单元格是否缺失,结合 ​​mean​​可以计算出每列缺失值的比例:

df = pd.read_csv('data/learn_pandas.csv', usecols=['Grade', 'Name', 'Gender', 'Height', 'Weight', 'Transfer'])
print('查看是否缺失\n', df.isna().head())
print('缺失的比例\n', df.isna().mean())

【Pandas】Pandas基础_数据挖掘_42

如果想要查看某一列缺失或者非缺失的行,可以利用 Series 上的 isna 或者 notna 进行布尔索引。例如,查看身高缺失的行:

print('身高缺失的行\n', df[df.Height.isna()].head())

【Pandas】Pandas基础_数据_43

如果想要同时对几个列,检索出全部为缺失或者至少有一个缺失或者没有缺失的行,可以使用​​isna​​,​​notna​​和 ​​any​​, ​​all​​ 的组合。例如,对身高、体重和转系情况这3列分别进行这三种情况的检索:

sub_set = df[['Height', 'Weight', 'Transfer']]
print('全部缺失\n', df[sub_set.isna().all(1)])
print('至少缺失一个\n', df[sub_set.isna().any(1)].head())
print('没有缺失\n', df[sub_set.notna().all(1)].head())

【Pandas】Pandas基础_数据分析_44

缺失值的删除

数据处理中经常需要根据缺失值的大小、比例或其他特征来进行行样本或列特征的删除, ​​pandas​​ 中提供了 ​​dropna​​函数来进行操作。

​dropna​​的主要参数为轴方向​​axis​​(默认为0,即删除行)、删除方式 how 、删除的非缺失值个数阈值 ​​thresh​​( 非缺失值 没有达到这个数量的相应维度会被删除)、备选的删除子集​​subset​​,其中how 主要有​​any​​和​​all​​两种参数可以选择。

例如,删除身高体重至少有一个缺失的行:

# 删除身高体重至少有一个缺失的行
res = df.dropna(how='any', subset=['Height', 'Weight'])
print('删除身高体重至少有一个缺失的行\n', res)

【Pandas】Pandas基础_数据分析_45

例如,删除超过15个缺失值的列:

res = df.dropna(1, thresh=df.shape[0] - 15)
print('删除超过15个缺失值的列\n', res)

【Pandas】Pandas基础_数据分析_46

​​跳转顶部​​

缺失值的填充

利用​​fillna​​进行填充

在 ​​fillna​​ 中有三个参数是常用的: ​​value​​, ​​method​​, ​​limit​​。其中, ​​value​​ 为填充值,可以是标量,也可以是索引到元素的字典映射; ​​method​​ 为填充方法,有用前面的元素填充​​ffill​​和用后面的元素填充​​bfill​​两种类型,​​limit​​参数表示连续缺失值的最大填充次数。

s = pd.Series([np.nan, 1, np.nan, np.nan, 2, np.nan], list('aaabcd'))
s.fillna(method='ffill') # 用前面的值向后填充
s.fillna(method='ffill', limit=1) # 连续出现的缺失,最多填充一次
s.fillna(s.mean()) # value为标量
s.fillna({'a': 100, 'd': 200}) # 通过索引映射填充的值

​​跳转顶部​​


举报

相关推荐

0 条评论