Task02_pandas基础

这一次的任务主要是熟悉api,了解各个函数的功能,难点还是在合理应用,还需从例子中多总结一些应用场景及特殊用法。

一、文件的读取和写入

1.文件读取

文件读取常用的函数是read_csvread_tableread_txt,分别对应的是读取csvexceltxt文件,举一个例子,其他几个函数用法类似:

import pandas as pd
import numpy as np

df_csv = pd.read_csv('data/my_csv.csv')
## 结果如下表
col1col2col3col4col5
02a1.4apple2020/1/1
13b3.4banana2020/1/2
26c2.5orange2020/1/5
35d3.2lemon2020/1/7

上述几个函数有一些常用的公共参数:

  • header=None:第一行不作为列名
  • index_col=list:把某一列或几列作为索引,相当于把一列或者几列固定下来,如上表第一列[0,1,2,3],查询数据时总是会有这一列,同样地,index_col中包含的列在查询数据时也总会有
  • usecols=list:读取列的集合,默认读取所有
  • parse_dates:表示需要转化为时间的列
  • nrows:读取数据行数

相关示例如下:

csv = pd.read_csv('data/my_csv.csv',index_col=['col1','col2'])
csv['col3']
## 结果如下
col1  col2
2     a       1.4
3     b       3.4
6     c       2.5
5     d       3.2
Name: col3, dtype: float64

pd.read_csv('data/my_csv.csv', usecols=['col1','col2', 'col5'], parse_dates=['col5'], nrows=3)
## 结果如下
	col1	col2	col5
0	2		a	2020-01-01
1	3		b	2020-01-02
2	6		c	2020-01-05

读取txt文件时常遇到非空格的分隔符,read_table中可以通过赋值一个正则表达式给sep参数实现自定义分割符号,例子如下:

pd.read_table('data/my_table_special_sep.txt')
## 结果如下
	col1 |||| col2
0	TS |||| This is an apple.
1	GQ |||| My name is Bob.
2	WT |||| Well done!
3	PT |||| May I help you?

pd.read_table('data/my_table_special_sep.txt', sep=' \|\|\|\| ', engine='python')
## 结果如下
	col1	col2
0	TS	This is an apple.
1	GQ	My name is Bob.
2	WT	Well done!
3	PT	May I help you?
2.数据写入

主要是有两个函数:df_csv.to_csv(path)df_excel.to_excel(path)pandas没有提供to_table函数,但是可以通过to_csv保存成txt文件,并且可以使用自定义分隔符。在进行写入操作时通常会把index设置为False,特别是当索引没有意义时。下面是课件中举的例子:

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

## 用csv函数保存为txt文件
df_txt.to_csv('data/my_txt_saved.txt', sep='\t', index=False)

二、基本数据结构

pandas有两种基本的数据结构,存储一维数据的Series和存储二维数据的DataFrame,分别记录一些常用的属性和方法方便日后查阅

1、Series

Series由四个部分组成,分别是序列的值data、索引index、存储类型dtype、序列的名字name,这些属性可以通过.的方式获取,比如s.index

Series大致可以看成是由key-value构成的一个表,key是索引值,value是存储的值,值得注意的在Series可以同时存储多种类型的数据

2、DataFrame

DataFrameSeries 的基础上增加了列索引,一个数据框可以由二维的 data 与行列索引来构造。

常见的取数据方式有以下两种:

  • [col_name]:取出一列数据,相当于Series
  • [col_list]:取出多列数据,还是一个DataFrame
df_csv = pd.read_csv('data/my_csv.csv')

df_csv['col1']
## 结果
0    2
1    3
2    6
3    5
Name: col1, dtype: int64

df_csv[['col1','col2']]
## 结果
	col1	col2
0	2		a
1	3		b
2	6		c
3	5		d

三、常用基本函数

下面的df为加载的一份数据集,是一个DataFrame对象

1、汇总函数
  • df.head(n):取前n行数据,默认n=5
  • df.tail(n):取后n行数据,默认n=5
  • df.info():返回表的信息概况,主要是列名、不为空的数量、列的数据类型
  • df.describe():返回表中列对应的主要统计量,countmeanstdmaxmin
2、特征统计函数

SeriesDataFrame 上定义了许多统计函数,从名字就很容易看出的就不写解释了:

  • df.sum()
  • df.mean()
  • df.median()
  • df.var()
  • df.std()
  • df.max()
  • df.min()
  • df.quantile(n)n分位数
  • df.count():非缺失值个数
  • df.idxmax():最大值对应的索引
  • df.mad():离差的均值,返回的是一个序列中偏离该序列均值的绝对值大小的均值

上述统计函数可以指定操作的维度axis,当axis=0时对每列进行操作,当axis=1时对每行进行操作,默认为0

3、唯一值函数
  • df[col_name].unique():以列表的形式返回该列属性值
  • df[col_name].unique():返回某列属性值个数
  • df[col_name].value_count():统计各属性值及其出现次数

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

In [60]: df_demo = df[['Gender','Transfer','Name']]
In [61]: df_demo.drop_duplicates(['Gender', 'Transfer'])
In [62]: df_demo.drop_duplicates(['Gender', 'Transfer'], keep='last')

此外, duplicateddrop_duplicates 的功能类似, drop_duplicates 等价于把 duplicatedTrue 的对应行剔除。课程中例子如下:

df_demo.duplicated(['Gender', 'Transfer']).head()
## 结果
0    False
1    False
2     True
3     True
4     True
dtype: bool

注意应用场景,合理的使用可以得到很好的效果,比如得到一个去重的DataFrame

4、替换函数

映射替换replace,用法如下:

bfill 则使用后面最近的未被替换的值进行替换## 传入字典的方式将Female替换成0,Male替换成1
df['Gender'].replace({'Female':0, 'Male':1}).head()

## 传入列表的方式将Female替换成0,Male替换成1
df['Gender'].replace(['Female', 'Male'], [0, 1]).head()

## 指定method 参数为 ffill 则为用前面一个最近的未被替换的值进行替换
s.replace([1, 2], method='ffill')

## bfill 则使用后面最近的未被替换的值进行替换
s.replace([1, 2], method='bfill')

逻辑替换:

  • where:传入条件为 False 的对应行进行替换
  • mask:传入条件为 True 的对应行进行替换

用法如下:

## 不指定替换值时默认用nan替换
s.where(s<0)

## 指定条件和替换值的用法
s.where(s<0, 100)

## mask函数与之类似
s.mask(s<0)
s.mask(s<0, -50)

## 传入条件替换的例子
## 传入的条件只需是与被调用的 Series 索引一致的布尔序列
s_condition= pd.Series([True,False,False,True],index=s.index)
s.mask(s_condition, -50)
5、排序函数

排序共有两种方式,其一为值排序,其二为索引排序,对应的函数是 sort_valuessort_index 。用法如下:

## ascending参数为True表示升序,为False表示降序,默认为True
df_demo.sort_values('Height', ascending=False).head()

## 对多个列进行组合排序
df_demo.sort_values(['Weight','Height'],ascending=[True,False]).head()

## 索引排序的用法和值排序完全一致,只不过元素的值在索引中,此时需要指定索引层的名字或者层号,用参数 level 表示
df_demo.sort_index(level=['Grade','Name'],ascending=[True,False]).head()
6、apply方法

apply 方法常用于 DataFrame 的行迭代或者列迭代,apply参数往往是一个以序列为输入的函数。用法如下:

## 这里的my_mean是一个函数名,可用lambda表达式来代替
df_demo.apply(my_mean)

若指定 axis=1 ,那么每次传入函数的就是行元素组成的Series

四、窗口对象

pandas中有3类窗口,分别是滑动窗口rolling、扩张窗口expanding以及指数加权窗口ewm

1、滑动窗口

要使用滑窗函数,就必须先要对一个序列使用.rolling得到滑窗对象,其最重要的参数为窗口大小window=n,相当于取n个数进行操作,不满足n的置为NaN,因此返回的序列前n-1个数为NaN。用法如下:

s = pd.Series([1,2,3,4,5])
roller = s.rolling(window = 3)

## 滑窗对象可以使用各种聚合函数
roller.mean()
roller.sum()
## 滑动相关系数或滑动协方差的计算需要传入第二个计算对象
roller.cov(s2)
roller.corr(s2)
## 滑窗对象还支持使用 apply 传入自定义函数,其传入值是对应窗口的 Series
roller.apply(lambda x:x.mean())

类滑窗函数,公共参数为 periods=n,这里的 n 可以为负,表示反方向的类似操作:

  • s.shift(n):向下移动n行
  • s.diff(n):与向前第 n 个元素做差
  • s.pct_change(n):与向前第 n 个元素相比计算增长率
2、扩张窗口

扩张窗口又称累计窗口,可以理解为一个动态长度的窗口,其窗口的大小就是从序列开始处到具体操作的对应位置,其使用的聚合函数会作用于这些逐步扩张的窗口上。具体地说,设序列为a1, a2, a3, a4,则其每个位置对应的窗口即[a1]、[a1, a2]、[a1, a2, a3]、[a1, a2, a3, a4]。教材中例子如下:

s = pd.Series([1, 3, 6, 10])
s.expanding().mean()

## 结果
0    1.000000
1    2.000000
2    3.333333
3    5.000000
dtype: float64

五、练习

Ex1:口袋妖怪数据集

1、对 HP, Attack, Defense, Sp. Atk, Sp. Def, Speed 进行加总,验证是否为 Total 值。

df = pd.read_csv('data/pokemon.csv')
df_demo = df[['HP','Attack','Defense', 'Sp. Atk', 'Sp. Def', 'Speed']]
df['Total'] == df_demo.sum(axis=1)

2、对于 # 重复的妖怪只保留第一条记录,解决以下问题:

df_demo = df.drop_duplicates(['#'], keep='first')

​ a.求第一属性的种类数量和前三多数量对应的种类

df_demo['Type 1'].nunique()
## 结果:18
df_demo['Type 1'].value_counts().head(3)
## 结果
Water     105
Normal     93
Grass      66
Name: Type 1, dtype: int64

​ b.求第一属性和第二属性的组合种类

df_demo[['Type 1','Type 2']].value_counts()
## 结果
Type 1    Type 2  
Normal    Flying      23
Grass     Poison      14
Bug       Flying      13
          Poison      11
Water     Ground       9
                      ..
Fighting  Dark         1
Psychic   Ghost        1
Ground    Electric     1
Electric  Ghost        1
Water     Steel        1
Length: 125, dtype: int64

​ c.求尚未出现过的属性组合

## 参考答案
## 得到所有组合数的列表
L_full = [i+" "+j for i in df_demo['Type 1'].unique() for j in (df_demo['Type 1'].unique() + [''])]
## 得到现有组合的列表
L_part = [i+" "+j for i,j in zip(df_demo['Type 1'], df_demo['Type 2'].replace(np.nan, ''))]
## 计算差集
res = set(L_full).difference(set(L_part))
len(res)

3、按照下述要求,构造 Series

​ a.取出物攻,超过120的替换为 high ,不足50的替换为 low ,否则设为 mid

df_attack = df['Attack']
df_attack.mask(df_attack < 50,'low').mask(df_attack > 120,'high').mask((df_attack>=50)&(df_attack<=120),'mid')

本来打算直接替换三次的,发现第二次替换之后有部分数据从int变成str了,因此报错,看了参考答案之后发现可以连续用,这样的实现方式确实很优雅

​ b.取出第一属性,分别用 replaceapply 替换所有字母为大写

df['Type 1'].str.upper()	

## 参考答案
df['Type 1'].replace({i:str.upper(i) for i in df['Type 1'].unique()}).head()
df['Type 1'].apply(lambda x:str.upper(x)).head()

没看清题目,看到答案一脸懵逼

​ c.求每个妖怪六项能力的离差,即所有能力中偏离中位数最大的值,添加到 df 并从大到小排序

df['mad'] = df[['HP','Attack','Defense','Sp. Atk','Sp. Def','Speed']].mad(axis=1)
df.sort_values(['mad'], ascending=False)
Ex2:指数加权窗口
  1. 作为扩张窗口的 ewm 窗口

在扩张窗口中,用户可以使用各类函数进行历史的累计指标统计,但这些内置的统计函数往往把窗口中的所有元素赋予了同样的权重。事实上,可以给出不同的权重来赋给窗口中的元素,指数加权窗口就是这样一种特殊的扩张窗口。

其中,最重要的参数是 alpha ,它决定了默认情况下的窗口权重为 w i = ( 1 − α ) i , i ∈ 0 , 1 , . . . , t w_i=(1−α)^i,i∈{0,1,...,t} wi=(1α)i,i0,1,...,t ,其中 i = t i=t i=t 表示当前元素, i = 0 i=0 i=0表示序列的第一个元素。

从权重公式可以看出,离开当前值越远则权重越小,若记原序列为 x ,更新后的当前元素为 y t y_t yt ,此时通过加权公式归一化后可知:

KaTeX parse error: No such environment: split at position 7: \begin{̲s̲p̲l̲i̲t̲}̲y_t &=\frac{\su…

对于 Series 而言,可以用 ewm 对象如下计算指数平滑后的序列:请用 expanding 窗口实现。

## 参考答案
def ewm_func(x, alpha=0.2):
    win = (1-alpha)**np.arange(len(x))[::-1]
    res = (win*x).sum()/win.sum()
    return res
s.expanding().apply(ewm_func).head()

## 结果
0   -1.000000
1   -1.000000
2   -1.262295
3   -1.390244
4   -1.464541
dtype: float64

想到了应该怎么用,没有想到怎么写apply的函数,还是python基础不太好,记录一下思路:这里利用列表实现累加,注意这里要从后往前取数,因为公式是xi * xt-i

  1. 作为滑动窗口的 ewm 窗口

从第1问中可以看到, ewm 作为一种扩张窗口的特例,只能从序列的第一个元素开始加权。现在希望给定一个限制窗口 n ,只对包含自身的最近的 n 个元素作为窗口进行滑动加权平滑。请根据滑窗函数,给出新的 wi 与 yt 的更新公式,并通过 rolling 窗口实现这一功能。

w i = ( 1 − α ) i , i ∈ 0 , 1 , . . . , n − 1 w_i=(1−α)^i,i∈{0,1,...,n-1} wi=(1α)i,i0,1,...,n1

KaTeX parse error: No such environment: split at position 7: \begin{̲s̲p̲l̲i̲t̲}̲y_t &=\frac{\su…

s.rolling(window=2).apply(ewm_func)

## 结果
0         NaN
1   -1.000000
2   -1.444444
3   -2.000000
4   -2.000000
dtype: float64
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值