task02_01

import numpy as np
import pandas as pd
pd.__version__
'1.1.5'

2.1.1

df_csv = pd.read_csv('my_csv.csv')
df_csv
col1 col2 col3 col4 col5
0 2 a 1.4 apple 2020/1/1
1 3 b 3.4 banana 2020/1/2
2 6 c 2.5 orange 2020/1/5
3 5 d 3.2 lemon 2020/1/7
df_txt = pd.read_table('my_table.txt')
df_txt
col1 col2 col3 col4
0 2 a 1.4 apple 2020/1/1
1 3 b 3.4 banana 2020/1/2
2 6 c 2.5 orange 2020/1/5
3 5 d 3.2 lemon 2020/1/7
df_excel = pd.read_excel('my_excel.xlsx')
df_excel
col1 col2 col3 col4 col5
0 2 a 1.4 apple 2020/1/1
1 3 b 3.4 banana 2020/1/2
2 6 c 2.5 orange 2020/1/5
3 5 d 3.2 lemon 2020/1/7
# header = None表示第一行不作为列名,相当于新增一行标识列号
pd.read_table('my_table.txt', header=None) 
0 1 2 3
0 col1 col2 col3 col4
1 2 a 1.4 apple 2020/1/1
2 3 b 3.4 banana 2020/1/2
3 6 c 2.5 orange 2020/1/5
4 5 d 3.2 lemon 2020/1/7
# index_col 表示把某一列或几列作为索引
# 理解是做group by?把['col2', 'col4']及对应的值当做一组,放到最左侧
# 然后用\n将这一组和其他的分开
pd.read_csv('my_csv.csv', index_col=['col2', 'col4']) 
col1 col3 col5
col2 col4
a apple 2 1.4 2020/1/1
b banana 3 3.4 2020/1/2
c orange 6 2.5 2020/1/5
d lemon 5 3.2 2020/1/7
# usecols 表示读取列的集合,默认读取所有的列
# 可以理解为,只有col1和col2的列is_use=True,所以不设定第二个参数时,所有列都会展示
pd.read_table('my_table.txt', usecols=['col1', 'col2']) 
col1 col2
0 2 a
1 3 b
2 6 c
3 5 d
# parse_dates 表示需要转化为时间的列
# 原列时间格式为2020/1/1,现在转为时间格式为2020-01-01
# 对于其他列的值,无法解析成时间格式
pd.read_csv('my_csv.csv', parse_dates=['col5']) 
col1 col2 col3 col4 col5
0 2 a 1.4 apple 2020-01-01
1 3 b 3.4 banana 2020-01-02
2 6 c 2.5 orange 2020-01-05
3 5 d 3.2 lemon 2020-01-07
# nrows 表示读取的数据行
# 默认从第0行开始读取
pd.read_excel('my_excel.xlsx', nrows=2) 
col1 col2 col3 col4 col5
0 2 a 1.4 apple 2020/1/1
1 3 b 3.4 banana 2020/1/2

在读取 txt 文件时,经常遇到分隔符非空格的情况,read_table 有一个分割参数 sep ,它使得用户可以自定义分割符号,进行 txt 数据的读取。

# 读取的表以 |||| 为分割
pd.read_table('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?
# 可以使用 sep ,同时需要指定引擎为 python 
# 在使用 read_table 的时候需要注意,参数 sep 中使用的是正则表达式,因此需要对 | 进行转义 变成 \| ,否则无法读取到正确的结果
# sep定义的直接是正则式的内容,匹配到该正则式的内容,则出去
pd.read_table('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.1.2 数据写入

# 把 index 设置为 False,特别当索引没有特殊意义的时候,这样的行为 能把索引在保存的时候去除。
df_csv.to_csv('my_csv_saved.csv', index=False)
df_excel.to_excel('my_excel_saved.xlsx', index=False)

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

df_txt.to_csv('my_txt_saved.txt', sep='\t', index=False)
# 把表格转换为markdown格式
print(df_csv.to_markdown())
|    |   col1 | col2   |   col3 | col4   | col5     |
|---:|-------:|:-------|-------:|:-------|:---------|
|  0 |      2 | a      |    1.4 | apple  | 2020/1/1 |
|  1 |      3 | b      |    3.4 | banana | 2020/1/2 |
|  2 |      6 | c      |    2.5 | orange | 2020/1/5 |
|  3 |      5 | d      |    3.2 | lemon  | 2020/1/7 |
# 把表格转换为latex格式
print(df_csv.to_latex()) 
\begin{tabular}{lrlrll}
\toprule
{} &  col1 & col2 &  col3 &    col4 &      col5 \\
\midrule
0 &     2 &    a &   1.4 &   apple &  2020/1/1 \\
1 &     3 &    b &   3.4 &  banana &  2020/1/2 \\
2 &     6 &    c &   2.5 &  orange &  2020/1/5 \\
3 &     5 &    d &   3.2 &   lemon &  2020/1/7 \\
\bottomrule
\end{tabular}

2.2 基本数据结构
pandas中具有两种基本的数据存储结构,存储一维values的Series和存储二维values的DataFrame
Series一般由四个部分组成,分别是序列的值data,索引index,存储类型dtype,序列的名字name
其中,索引也可以指定它的名字,默认为空。

a = pd.Series(data = [100, 'a', {'dict1':5}], 
              index = pd.Index(['id1',20,'third'], name='my_idx'),
              dtype = 'object',
              name = 'my_name')
a
my_idx
id1               100
20                  a
third    {'dict1': 5}
Name: my_name, dtype: object

object 类型 object代表了一种混合类型,正如上面的例子中存储了整数、字符串以及Python的字典数据结构。
此外,目前pandas把纯字符串序列也默认认为是一种object类型的序列,但它也可以用string类型存储。

# 属性可以通过.的方式来获取
# 返回array类型的结果,类型是混合类型object
a.values
array([100, 'a', {'dict1': 5}], dtype=object)
# index会返回索引,object类型和序列名字
a.index
Index(['id1', 20, 'third'], dtype='object', name='my_idx')
# 表示是一个python对象
a.dtype
dtype('O')
a.name
'my_name'
# (3,)表示第一维是3,第二个参数缺省
# 获取序列的长度
a.shape
(3,)
# 取出单个索引对应的值,[]中是索引
a['third']
{'dict1': 5}

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

# 在字符串中用%d,类似于.format的用法,就是规定字符串中的数可以由变量来表示
# 字符串中 %d规定输出的是数字,字符串外层也用%i来表示变量
# 另一种是用枚举方式表示列值
data = [[1, 'a', 1.2], [2, 'b', 2.2], [3, 'c', 3.2]]
df = pd.DataFrame(data = data,
                  index = ['row_%d'%i for i in range(3)],
                  columns = ['col_0', 'col_1', 'col_2'])
df
col_0 col_1 col_2
row_0 1 a 1.2
row_1 2 b 2.2
row_2 3 c 3.2

但一般而言,更多的时候会采用从列索引名到数据的映射来构造数据框,同时再加上行索引

df = pd.DataFrame(data = {'col_0':[1,2,3],'col_1':list('abc'),'col_2':[1.2,2.2,3.2]},
                  index = ['row_%d' %i for i in range(3)])
df
col_0 col_1 col_2
row_0 1 a 1.2
row_1 2 b 2.2
row_2 3 c 3.2

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

# 相当于只取col_0这一列的值
df['col_0']
row_0    1
row_1    2
row_2    3
Name: col_0, dtype: int64
# 用list表示取多列的值
df[['col_0','col_2']]
col_0 col_2
row_0 1 1.2
row_1 2 2.2
row_2 3 3.2
df.values
array([[1, 'a', 1.2],
       [2, 'b', 2.2],
       [3, 'c', 3.2]], dtype=object)
df.index
Index(['row_0', 'row_1', 'row_2'], dtype='object')
df.columns
Index(['col_0', 'col_1', 'col_2'], dtype='object')
# 返回的是值为相应列数据类型的 Series
df.dtypes
col_0      int64
col_1     object
col_2    float64
dtype: object
# 可以把DataFrame进行转置
df.T
row_0 row_1 row_2
col_0 1 2 3
col_1 a b c
col_2 1.2 2.2 3.2

2.3 常用基本函数

df = pd.read_csv('learn_pandas.csv')
# 上述列名依次代表学校、年级、姓名、性别、身高、体重、是否为转系生、体测场次、测试时间、1000 米成绩
df.columns
Index(['School', 'Grade', 'Name', 'Gender', 'Height', 'Weight', 'Transfer',
       'Test_Number', 'Test_Date', 'Time_Record'],
      dtype='object')
# df整张表中,取表的前7列
df = df[df.columns[:7]]
df
School Grade Name Gender Height Weight Transfer
0 Shanghai Jiao Tong University Freshman Gaopeng Yang Female 158.9 46.0 N
1 Peking University Freshman Changqiang You Male 166.5 70.0 N
2 Shanghai Jiao Tong University Senior Mei Sun Male 188.9 89.0 N
3 Fudan University Sophomore Xiaojuan Sun Female NaN 41.0 N
4 Fudan University Sophomore Gaojuan You Male 174.0 74.0 N
... ... ... ... ... ... ... ...
195 Fudan University Junior Xiaojuan Sun Female 153.9 46.0 N
196 Tsinghua University Senior Li Zhao Female 160.9 50.0 N
197 Shanghai Jiao Tong University Senior Chengqiang Chu Female 153.9 45.0 N
198 Shanghai Jiao Tong University Senior Chengmei Shen Male 175.3 71.0 N
199 Tsinghua University Sophomore Chunpeng Lv Male 155.7 51.0 N

200 rows × 7 columns

2.3.1 汇总函数

# head,tail函数分别表示返回表或者序列的前n行和后n行,其中n默认为 5
df.head(4)
School Grade Name Gender Height Weight Transfer
0 Shanghai Jiao Tong University Freshman Gaopeng Yang Female 158.9 46.0 N
1 Peking University Freshman Changqiang You Male 166.5 70.0 N
2 Shanghai Jiao Tong University Senior Mei Sun Male 188.9 89.0 N
3 Fudan University Sophomore Xiaojuan Sun Female NaN 41.0 N
df.tail(4)
School Grade Name Gender Height Weight Transfer
196 Tsinghua University Senior Li Zhao Female 160.9 50.0 N
197 Shanghai Jiao Tong University Senior Chengqiang Chu Female 153.9 45.0 N
198 Shanghai Jiao Tong University Senior Chengmei Shen Male 175.3 71.0 N
199 Tsinghua University Sophomore Chunpeng Lv Male 155.7 51.0 N
# info返回表的信息概况
# info主要展示列的信息, 统计每列有多少非空,以及数据类型
df.info()

RangeIndex: 200 entries, 0 to 199
Data columns (total 7 columns):
 #   Column    Non-Null Count  Dtype  
---  ------    --------------  -----  
 0   School    200 non-null    object 
 1   Grade     200 non-null    object 
 2   Name      200 non-null    object 
 3   Gender    200 non-null    object 
 4   Height    183 non-null    float64
 5   Weight    189 non-null    float64
 6   Transfer  188 non-null    object 
dtypes: float64(2), object(5)
memory usage: 11.1+ KB
# describe返回的是表中数值列对应的主要统计量
# 计数,平均值,标准差,最小值,最大值以及较低的百分位数和50。默认情况下,较低的百分位数为25,较高的百分位数为75.50百分位数与中位数相同
df.describe()
Height Weight
count 183.000000 189.000000
mean 163.218033 55.015873
std 8.608879 12.824294
min 145.400000 34.000000
25% 157.150000 46.000000
50% 161.900000 51.000000
75% 167.500000 65.000000
max 193.900000 89.000000
# 这个参数默认是只计算数值型特征的统计量,当输入include=['O'],会计算离散型变量的统计特征
# 直接给出了非空数量count,唯一值种类unique,出现最多的类型top和出现次数freq
df.describe(include = ['O'])
School Grade Name Gender Transfer
count 200 200 200 200 188
unique 4 4 170 2 2
top Tsinghua University Junior Xiaoqiang Qin Female N
freq 69 59 3 141 181

2.3.2 特征统计函数
操作后返回的是标量,所以又称为聚合函数,它们有一个公共参数axis
默认0代表逐列聚合,设为则表示逐行聚合

df_stat = df[['Height','Weight']]
# mean()求平均
df_stat.mean()
Height    163.218033
Weight     55.015873
dtype: float64
# max()求最大值
df_stat.max()
Height    193.9
Weight     89.0
dtype: float64
# 分位数,分位数指的就是连续分布函数中的一个点,这个点对应概率p
df_stat.quantile(0.75)
Height    167.5
Weight     65.0
Name: 0.75, dtype: float64
# 非缺失值个数,统计有值的函数
df_stat.count()
Height    183
Weight    189
dtype: int64
# 最大值对应的索引!是索引,不是数值 
df_stat.idxmax()
Height    193
Weight      2
dtype: int64
# 最小值对应的索引
df_stat.idxmin()
Height    143
Weight     49
dtype: int64
# 但在这个数据集上求行(体重和身高)的均值,没有太大意义
df_stat.mean(axis=1).head()
0    102.45
1    118.25
2    138.95
3     41.00
4    124.00
dtype: float64

2.3.3 唯一值函数

# 对序列使用unique可以得到其唯一值组成的列表
df['School'].unique()
array(['Shanghai Jiao Tong University', 'Peking University',
       'Fudan University', 'Tsinghua University'], dtype=object)
# 对序列使用nunique可以得到唯一值的个数
df['School'].nunique()
4
# value_counts可以得到某一列的唯一值和其对应出现的频数
df['School'].value_counts()
Tsinghua University              69
Shanghai Jiao Tong University    57
Fudan University                 40
Peking University                34
Name: School, dtype: int64
#  drop_duplicates可以观察多个列组合的唯一值
# keep参数,默认值first表示每个组合保留第一次出现的所在行
# last表示保留最后一次出现的所在行
# false表示把所有重复组合所在的行剔除
# drop_duplicates返回了唯一值的布尔列表
df_stat = df[['Gender','Transfer','Name']]
df_stat.drop_duplicates(['Gender','Transfer'])
Gender Transfer Name
0 Female N Gaopeng Yang
1 Male N Changqiang You
12 Female NaN Peng You
21 Male NaN Xiaopeng Shen
36 Male Y Xiaojuan Qin
43 Female Y Gaoli Feng
df_stat.drop_duplicates(['Gender','Transfer'], keep='last')
Gender Transfer Name
147 Male NaN Juan You
150 Male Y Chengpeng You
169 Female Y Chengquan Qin
194 Female NaN Yanmei Qian
197 Female N Chengqiang Chu
199 Male N Chunpeng Lv
# 保留只出现过一次的性别和姓名的组合
df_stat.drop_duplicates(['Name','Gender'], keep=False).head()
Gender Transfer Name
0 Female N Gaopeng Yang
1 Male N Changqiang You
2 Male N Mei Sun
4 Male N Gaojuan You
5 Female N Xiaoli Qian
df['School'].drop_duplicates()
0    Shanghai Jiao Tong University
1                Peking University
3                 Fudan University
5              Tsinghua University
Name: School, dtype: object
df_stat.duplicated(['Gender', 'Transfer']).head()
0    False
1    False
2     True
3     True
4     True
dtype: bool
# duplicate把重复元素设为True,否则为False
# drop_duplicates等价于把 duplicated为True 的对应行剔除
# 有重复值是True,没重复值是False
# 筛选Gender和Transfer的组合种类
df_stat.duplicated(['Gender','Transfer']).head()
0    False
1    False
2     True
3     True
4     True
dtype: bool
df['School'].duplicated().head()
0    False
1    False
2     True
3    False
4     True
Name: School, dtype: bool

2.3.4 替换函数
替换操作是针对某一个列进行的
映射替换、逻辑替换、数值替换

# 在 replace 中,可以通过字典构造,或者传入两个列表来进行替换
df['Gender'].replace({'Female':0, 'Male':1}).head()
0    0
1    1
2    1
3    0
4    1
Name: Gender, dtype: int64
# replace中的参数相当于,第一个参数列表是字典的 key,第二个参数列表是字典的value
df['Gender'].replace(['Female','Male'],[0,1]).head()
0    0
1    1
2    1
3    0
4    1
Name: Gender, dtype: int64

replace还有一种特殊的方向替换,指定method参数为ffill,则为用前面一个最近的未被替换的值进行替换;bfill则使用后面最近的未被替换的值进行替换

# 把1和2替换成前面的值
a = pd.Series(['a',1,'b',2,1,1,'a'])
a.replace([1,2], method='ffill')
0    a
1    a
2    b
3    b
4    b
5    b
6    a
dtype: object
# 把1,2替换成后面的值
a.replace([1,2], method='bfill')
0    a
1    b
2    b
3    a
4    a
5    a
6    a
dtype: object

正则替换需使用str.replace

逻辑替换包括了where和mask,这两个函数是完全对称的
where函数在传入条件为False的对应行进行替换,而mask在传入条件为True的对应行进行替换
当不指定替换行时,替换为缺失值
a = pd.Series([-1,1.2345,100,-50])
# where传入不小于0时,进行替换,不指定替换行时,替换为缺失值NaN
a.where(a<0)
0    -1.0
1     NaN
2     NaN
3   -50.0
dtype: float64
# mask传入值小于0时,进行替换,不指定替换行时,替换为缺失值NaN
a.mask(a<0)
0         NaN
1      1.2345
2    100.0000
3         NaN
dtype: float64
# mask传入值小于0时,进行替换,指定替换内容为-50,替换为-50.0000
a.mask(a<0, -50)
0    -50.0000
1      1.2345
2    100.0000
3    -50.0000
dtype: float64
# 传入的条件只需是与被调用的Series索引一直的布尔序列即可
# mask函数为True时,替换第二个参数的值
a_condition = pd.Series([True,False,False,True], index=a.index)
a.mask(a_condition, -50)
0    -50.0000
1      1.2345
2    100.0000
3    -50.0000
dtype: float64

数值替换包含了round,abs,clip方法,分别表示取整,取绝对值和截断

# round可以用参数指定保留小数点后几位数字
a =pd.Series([-1,1.2345,100,-50])
a.round(2)
0     -1.00
1      1.23
2    100.00
3    -50.00
dtype: float64
# abs()取绝对值
a.abs()
0      1.0000
1      1.2345
2    100.0000
3     50.0000
dtype: float64
# 两个数表示上下截断边界
# 如,第一个数-1.00,小于下边界数0,则返回下边界数0
# 第二个数在[0,2],所以保留原数
# 第三个数为100,高于上边界数2,则返回上边界数2
a.clip(0,2)
0    0.0000
1    1.2345
2    2.0000
3    0.0000
dtype: float64

2.3.5排序函数
1.值排序sort_values
2.索引排序sort_index

# set_index方法把年级和姓名两列作为索引
df_index = df[['Grade','Name','Height','Weight']].set_index(['Grade','Name'])
df_index
Height Weight
Grade Name
Freshman Gaopeng Yang 158.9 46.0
Changqiang You 166.5 70.0
Senior Mei Sun 188.9 89.0
Sophomore Xiaojuan Sun NaN 41.0
Gaojuan You 174.0 74.0
... ... ... ...
Junior Xiaojuan Sun 153.9 46.0
Senior Li Zhao 160.9 50.0
Chengqiang Chu 153.9 45.0
Chengmei Shen 175.3 71.0
Sophomore Chunpeng Lv 155.7 51.0

200 rows × 2 columns

# 对身高进行排序,默认参数ascending=True为升序
df_index.sort_values('Height').head()
Height Weight
Grade Name
Junior Xiaoli Chu 145.4 34.0
Senior Gaomei Lv 147.3 34.0
Sophomore Peng Han 147.8 34.0
Senior Changli Lv 148.7 41.0
Sophomore Changjuan You 150.5 40.0
# 降序
df_index.sort_values('Height',ascending=False).head()
Height Weight
Grade Name
Senior Xiaoqiang Qin 193.9 79.0
Mei Sun 188.9 89.0
Gaoli Zhao 186.5 83.0
Freshman Qiang Han 185.3 87.0
Senior Qiang Zheng 183.9 87.0
# 在体重相同的情况下,对身高进行排序,并且保持身高降序排列,体重升序排列
df_index.sort_values(['Weight','Height'],ascending=[True,False]).head()
Height Weight
Grade Name
Sophomore Peng Han 147.8 34.0
Senior Gaomei Lv 147.3 34.0
Junior Xiaoli Chu 145.4 34.0
Sophomore Qiang Zhou 150.5 36.0
Freshman Yanqiang Xu 152.4 38.0
# 索引排序,元素的值在索引中,需要指定索引层的名字或者层号,用参数level表示
# 这里通过指定索引层的名字来表示,字符串的排列顺序是由字母顺序决定的
#  所以Grade是从F开始排序,Name是从Y开头的词排序
df_index.sort_index(level=['Grade','Name'],ascending=[True,False]).head()
Height Weight
Grade Name
Freshman Yanquan Wang 163.5 55.0
Yanqiang Xu 152.4 38.0
Yanqiang Feng 162.3 51.0
Yanpeng Lv NaN 65.0
Yanli Zhang 165.1 52.0
# level用层号表示,同样的结果
df_index.sort_index(level=[0,1],ascending=[True,False]).head()
Height Weight
Grade Name
Freshman Yanquan Wang 163.5 55.0
Yanqiang Xu 152.4 38.0
Yanqiang Feng 162.3 51.0
Yanpeng Lv NaN 65.0
Yanli Zhang 165.1 52.0

2.3.6 apply方法
apply常用于DataFrame的行迭代和列迭代
apply的参数往往是一个以序列为输入的函数

df_apply = df[['Height','Weight']]
def my_mean(x):
    res = x.mean()
    return res
# 对Height和Weight进行迭代
df_apply.apply(my_mean)
163.21803278688526
55.01587301587302





Height    163.218033
Weight     55.015873
dtype: float64
# 简单的函数可以转换成一行的隐形函数lambda表示
df_apply.apply(lambda x:x.mean())
Height    163.218033
Weight     55.015873
dtype: float64
# 指定axis=1,那么每次传入函数的就是行元素组成的Series
# 同逐行均值结果一致
df_apply.apply(lambda x:x.mean(),axis=1).head()
0    102.45
1    118.25
2    138.95
3     41.00
4    124.00
dtype: float64
# mad函数返回的是一个序列中偏离该序列均值的绝对值大小的均值
# 序列1,3,7,10中,均值为5.25,每一个元素偏离的绝对值为4.25,2.25,1.75,4.75,这个偏离序列的均值为3.25
# mad的解释示例:
df_apply.apply(lambda x:(x-x.mean()).abs().mean())
Height     6.707229
Weight    10.391870
dtype: float64
# mad直接调用方法,返回结果和上述一致
df_apply.mad()
Height     6.707229
Weight    10.391870
dtype: float64

note
使用pandas的内置函数处理和apply来处理同一个任务,速度会相差很多,所以要谨慎使用apply。2.4 窗口对象
pandas有3类窗口
滑动窗口rolling、扩张窗口expanding、指数加权窗口ewm要使用滑动窗口,就必须先要对一个序列使用.rolling得到滑窗对象
最重要的参数为窗口大小window

a=pd.Series([1,2,3,4,5])
roller=a.rolling(window=3)
roller
Rolling [window=3,center=False,axis=0]

得到滑窗对象后,能够使用相应的聚合函数进行计算
窗口包含当前行所在的元素
如,在第4个位置进行均值计算时,应当计算(2+3+4)/3,而不是(1+2+3)/3

# nan,nan,1->nan
# nan,1,2->nan
# 1,2,3->2.0
# 2,3,4->3.0
# 3,4,5->4.0
# 总结:有nan的时候返回nan
roller.mean()
0    NaN
1    NaN
2    2.0
3    3.0
4    4.0
dtype: float64
roller.sum()
0     NaN
1     NaN
2     6.0
3     9.0
4    12.0
dtype: float64
# 滑动相关系数的计算
s = pd.Series([1,2,6,16,30])
roller.cov(s)
0     NaN
1     NaN
2     2.5
3     7.0
4    12.0
dtype: float64
# 滑动协方差的计算
roller.corr(s)
0         NaN
1         NaN
2    0.944911
3    0.970725
4    0.995402
dtype: float64
# 支持使用apply传入自定义函数,其传入值是对应窗口的Series
roller.apply(lambda x:x.mean())
0    NaN
1    NaN
2    2.0
3    3.0
4    4.0
dtype: float64

shift,diff,pct_change是一组类滑窗函数,它们的公共参数为perids=n,默认为1,分别表示取向前第n个元素的值、与向前第n个元素做差(n阶差分)、与向前第n个元素相比计算增长率。这里的n可以为负,表示反方向的类似操作

a=pd.Series([1,3,6,10,15])
# 取向前第n个元素的值
# 1,3,6,10,15
# 每个位置向左数两个数:nan,nan,1,3,6
a.shift(2)
0    NaN
1    NaN
2    1.0
3    3.0
4    6.0
dtype: float64
# 与向前第n个元素做差(n阶差分)
# 1,3,6,10,15
# 1-nan->nan,3-nan->nan, 6-nan->nan, 10-1->9, 15-3->12
a.diff(3)
0     NaN
1     NaN
2     NaN
3     9.0
4    12.0
dtype: float64
# 与向前第n个元素相比计算增长率
# 1,3,6,10,15
# (1-nan)/nan->nan, (3-1)/1->2, (6-3)/3->1, (10-6)/6->0.66,(15-10)/6->0.5
a.pct_change()
0         NaN
1    2.000000
2    1.000000
3    0.666667
4    0.500000
dtype: float64
# 1,3,6,10,15
# 每个位置向后数一个数:3,6,10,15,nan
a.shift(-1)
0     3.0
1     6.0
2    10.0
3    15.0
4     NaN
dtype: float64
# 与向后第n个元素做差(n阶差分)
# 1,3,6,10,15
# 1-6->-5, 3-10->-7, 6-15->-9, 10-nan->nan, 15-nan->nan
a.diff(-2)
0   -5.0
1   -7.0
2   -9.0
3    NaN
4    NaN
dtype: float64

结合上面滑动窗口rolling,有没有发现它们的功能可以用窗口大小为n+1的rolling方法等价代替呢

# a.shift(2)
# 如果隐式函数不加list(x)[0],会报错cannot convert the series to 
s.rolling(3).apply(lambda x:list(x)[0])
0    NaN
1    NaN
2    1.0
3    2.0
4    6.0
dtype: float64
# s.diff
s.rolling(4).apply(lambda x:list(x)[-1]-list(x)[0])
0     NaN
1     NaN
2     NaN
3    15.0
4    28.0
dtype: float64
# s.pct_change()
def my_pct(x):
    L = list(x)
    return L[-1]/L[0]-1
s.rolling(2).apply(my_pct)
0         NaN
1    1.000000
2    2.000000
3    1.666667
4    0.875000
dtype: float64

思考题:
rolling对象的默认窗口方向都是向前的,某些情况下用户需要向后的窗口,例如对 1,2,3设定向后窗口为 2 的 sum 操作,结果为 3,5,NaN,此时应该如何实现向后的滑窗操作?(提示:使用shift )
感谢群里大佬提供思路!

# 群里的思路
# 相当于当前值+后面的值
# 1+2->3, 2+3->5, 3+nan->nan
t=pd.Series([1,2,3])
t+t.shift(-1)
0    3.0
1    5.0
2    NaN
dtype: float64
# 群里提供的解法
# 3,2,1
# 3,2,1->nan,3,2
# 累加:nan,5,3
# 逆序 3,5,nan
(t[::-1]+t[::-1].shift(1))[::-1]
0    3.0
1    5.0
2    NaN
dtype: float64

2.4.2 扩张窗口
累计窗口,可以理解为一个动态长度的窗口,其窗口的大小就是从序列开始处,到具体操作的对应位置
其使用的聚合函数会作用于这些逐步扩张的窗口上

设序列为a1,a2,a3,a4,则其每个位置对应的窗口即[a1]、[a1,a2]、[a1,a2,a3]、[a1,a2,a3,a4]

# 1->1,(1+3)/2->2,(1+3+6)/3>3.33,(1+3+6+10)/4->5
a = pd.Series([1,3,6,10])
a.expanding().mean()
0    1.000000
1    2.000000
2    3.333333
3    5.000000
dtype: float64

task01

df = pd.read_csv('pokemon.csv')
df.head(3)
# Name Type 1 Type 2 Total HP Attack Defense Sp. Atk Sp. Def Speed
0 1 Bulbasaur Grass Poison 318 45 49 49 65 65 45
1 2 Ivysaur Grass Poison 405 60 62 63 80 80 60
2 3 Venusaur Grass Poison 525 80 82 83 100 100 80
# 对HP,ATTACK,DEFENSE,SP,ATK,SP.Def,SPEED进行加总,验证是否为Total值
# 注意,用索引判断的话,需要将末尾列+1,相当于原本是5,6,7,8,9,10行,但是右括号是开区间,[5,11)
# 否则结果是1.0
# 用mean的话返回0.0,用max和min的话返回的是False
df = pd.read_csv('pokemon.csv')
(df[df.columns[5:11]].sum(axis=1) != df[df.columns[4]]).max()

False
# 答案
(df[['HP', 'Attack', 'Defense', 'Sp. Atk', 'Sp. Def', 'Speed'
 ]].sum(1)!=df['Total']).mean()
0.0

对于# 重复的妖怪值保留第一条记录
2.a 求第一属性的种类数量和前三多数量对应的种类

df = pd.read_csv('pokemon.csv')
df['Type 1'].value_counts().head(3)
Water     112
Normal     98
Grass      70
Name: Type 1, dtype: int64
# 对于# 重复的妖怪值保留第一条记录
df_dup = df.drop_duplicates('#', keep='first')
df_dup
# Name Type 1 Type 2 Total HP Attack Defense Sp. Atk Sp. Def Speed
0 1 Bulbasaur Grass Poison 318 45 49 49 65 65 45
1 2 Ivysaur Grass Poison 405 60 62 63 80 80 60
2 3 Venusaur Grass Poison 525 80 82 83 100 100 80
4 4 Charmander Fire NaN 309 39 52 43 60 50 65
5 5 Charmeleon Fire NaN 405 58 64 58 80 65 80
... ... ... ... ... ... ... ... ... ... ... ...
793 717 Yveltal Dark Flying 680 126 131 95 131 98 99
794 718 Zygarde50% Forme Dragon Ground 600 108 100 121 81 95 95
795 719 Diancie Rock Fairy 600 50 100 150 100 150 50
797 720 HoopaHoopa Confined Psychic Ghost 600 80 110 60 150 130 70
799 721 Volcanion Fire Water 600 80 110 120 130 90 70

721 rows × 11 columns

# 求第一属性的种类数量
# nunique得到唯一值的个数
df_dup['Type 1'].nunique()
18
# 前三多数量对应的种类
df_dup['Type 1'].value_counts().head(3)
Water     105
Normal     93
Grass      66
Name: Type 1, dtype: int64
# 答案
df_dup['Type 1'].value_counts().index[:3]
Index(['Water', 'Normal', 'Grass'], dtype='object')

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

# shape获取序列的长度,.shape结果是(143,11),11是原本的列数,只需取143,即为行数
df_attr = df_dup.drop_duplicates(['Type 1','Type 2'])
df_attr.shape[0]
143

求尚未出现过的属性组合
我的思路:找到Type 1和Type 2的组合,将所有出现过Type 1和Type 2排列组合,然后将组合数减去已有的组合

# 答案给的思路
# 之后还要再想一想
pd_full = [' '.join([i,j]) if i!=j else i for j in df_dup['Type 1'].unique() for i in df_dup['Type 1'].unique()]
pd_part = [' '.join([i,j]) if type(j)!=float else i for i,j in zip(df_attr['Type 1'], df_attr['Type 2'])]
result = set(pd_full).difference(set(pd_part))
len(result)
181

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

df['Attack'].mask(df['Attack']>120,'high').mask(df['Attack']<50,'low').mask((df['Attack']>=50)&(df['Attack']<=120), 'mid')
0       low
1       mid
2       mid
3       mid
4       mid
       ... 
795     mid
796    high
797     mid
798    high
799     mid
Name: Attack, Length: 800, dtype: object

取出第一属性,分别用replace和apply替换所有字母为大写

# 换成大写查到了str.upper的用法
df['Type 1'].replace({i:str.upper(i) for i in df['Type 1']})
0        GRASS
1        GRASS
2        GRASS
3        GRASS
4         FIRE
        ...   
795       ROCK
796       ROCK
797    PSYCHIC
798    PSYCHIC
799       FIRE
Name: Type 1, Length: 800, dtype: object
df['Type 1'].apply(lambda x:str.upper(x))
0        GRASS
1        GRASS
2        GRASS
3        GRASS
4         FIRE
        ...   
795       ROCK
796       ROCK
797    PSYCHIC
798    PSYCHIC
799       FIRE
Name: Type 1, Length: 800, dtype: object

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

# 求所有能力中位数,变成array
# 遍历每一行,对每一行的每一个值和中位数做差,因为是求偏离的最大值,所以应该为差的绝对值
# apply第二个参数axis应设为1,以行遍历
df['Dev']=df[df.columns[5:11]].apply(lambda x:  np.max((x-x.median()).abs()), axis=1)
df.sort_values('Dev',ascending=False)
# Name Type 1 Type 2 Total HP Attack Defense Sp. Atk Sp. Def Speed Deviation Dev
230 213 Shuckle Bug Rock 505 20 10 230 10 230 5 215.0 215.0
121 113 Chansey Normal NaN 450 250 5 5 35 105 50 207.5 207.5
261 242 Blissey Normal NaN 540 255 10 10 75 135 55 190.0 190.0
333 306 AggronMega Aggron Steel NaN 630 70 140 230 60 80 50 155.0 155.0
224 208 SteelixMega Steelix Steel Ground 610 75 125 230 55 95 30 145.0 145.0
... ... ... ... ... ... ... ... ... ... ... ... ... ...
143 132 Ditto Normal NaN 288 48 48 48 48 48 48 0.0 0.0
165 151 Mew Psychic NaN 600 100 100 100 100 100 100 0.0 0.0
255 236 Tyrogue Fighting NaN 210 35 35 35 35 35 35 0.0 0.0
206 191 Sunkern Grass NaN 180 30 30 30 30 30 30 0.0 0.0
271 251 Celebi Psychic Grass 600 100 100 100 100 100 100 0.0 0.0

800 rows × 13 columns

# 答案
df['Deviation'] = df[['HP', 'Attack', 'Defense', 'Sp. Atk','Sp. Def', 'Speed']].apply(lambda x:
 np.max((x-x.median()).abs()), 1)
df.sort_values('Deviation', ascending=False).head()
# Name Type 1 Type 2 Total HP Attack Defense Sp. Atk Sp. Def Speed Deviation
230 213 Shuckle Bug Rock 505 20 10 230 10 230 5 215.0
121 113 Chansey Normal NaN 450 250 5 5 35 105 50 207.5
261 242 Blissey Normal NaN 540 255 10 10 75 135 55 190.0
333 306 AggronMega Aggron Steel NaN 630 70 140 230 60 80 50 155.0
224 208 SteelixMega Steelix Steel Ground 610 75 125 230 55 95 30 145.0

2.5.2 指数加权窗口

# 题目
np.random.seed(0)
s = pd.Series(np.random.randint(-1,2,30).cumsum()).head()
s.ewm(alpha = 0.2).mean().head()
0   -1.000000
1   -1.000000
2   -1.409836
3   -1.609756
4   -1.725845
dtype: float64
# 套用公式
alpha = 0.2
s.expanding().apply(lambda x: ((1-alpha)**np.arange(x.shape[0])*x[::-1]).sum()
                                    / ((1-alpha) ** np.arange(shape[0])).sum())
0   -1.000000
1   -1.000000
2   -1.409836
3   -1.609756
4   -1.725845
dtype: float64

给定一个限制窗口n,只对包含自身最近的n个窗口进行滑动加权平均,给出新的wi和yt的更新公式,并通过rolling窗口实现这一功能
我的思路:和上一问一样,只是加了窗口限定的数值n,假设取n为3

alpha = 0.2
s.rolling(window=3).apply(lambda x: ((1-alpha)**np.arange(3)*x[::-1]).sum()
                                    / ((1-alpha) ** np.arange(3)).sum())
0         NaN
1         NaN
2   -1.409836
3   -1.737705
4   -2.000000
dtype: float64

你可能感兴趣的:(python初学笔记,pandas)