编程实践(Pandas) Task02

一、文件的读取和写入

excel csv txt
文件读取 pd.read_excel() pd.read_csv() pd.read_table()
数据写入 to_excel() to_csv() to_csv()

1. 文件读取

  • csv文件读取:pd.read_csv

pandas.read_csv(filepath_or_buffer, sep=’,’, delimiter=None, header=‘infer’, names=None, index_col=None, usecols=None, squeeze=False, prefix=None, mangle_dupe_cols=True, dtype=None, engine=None, converters=None, true_values=None, false_values=None, skipinitialspace=False, skiprows=None, skipfooter=0, nrows=None, na_values=None, keep_default_na=True, na_filter=True, verbose=False, skip_blank_lines=True, parse_dates=False, infer_datetime_format=False, keep_date_col=False, date_parser=None, dayfirst=False, cache_dates=True, iterator=False, chunksize=None, compression=‘infer’, thousands=None, decimal=’.’, lineterminator=None, quotechar=’"’, quoting=0, doublequote=True, escapechar=None, comment=None, encoding=None, dialect=None, error_bad_lines=True, warn_bad_lines=True, delim_whitespace=False, low_memory=True, memory_map=False, float_precision=None)

df_csv = pd.read_csv("Data/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
  • txt文件读取:pd.read_table

pandas.read_table(filepath_or_buffer, sep=’\t’, delimiter=None, header=‘infer’, names=None, index_col=None, usecols=None, squeeze=False, prefix=None, mangle_dupe_cols=True, dtype=None, engine=None, converters=None, true_values=None, false_values=None, skipinitialspace=False, skiprows=None, skipfooter=0, nrows=None, na_values=None, keep_default_na=True, na_filter=True, verbose=False, skip_blank_lines=True, parse_dates=False, infer_datetime_format=False, keep_date_col=False, date_parser=None, dayfirst=False, cache_dates=True, iterator=False, chunksize=None, compression=‘infer’, thousands=None, decimal=’.’, lineterminator=None, quotechar=’"’, quoting=0, doublequote=True, escapechar=None, comment=None, encoding=None, dialect=None, error_bad_lines=True, warn_bad_lines=True, delim_whitespace=False, low_memory=True, memory_map=False, float_precision=None)

df_txt = pd.read_table('data/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
  • excel文件读取:pd.read_excel

pandas.read_excel(io, sheet_name=0, header=0, names=None, index_col=None, usecols=None, squeeze=False, dtype=None, engine=None, converters=None, true_values=None, false_values=None, skiprows=None, nrows=None, na_values=None, keep_default_na=True, na_filter=True, verbose=False, parse_dates=False, date_parser=None, thousands=None, comment=None, skipfooter=0, convert_float=True, mangle_dupe_cols=True)

df_excel = pd.read_excel('data/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 int, list of int, default 0 指定作为列名的行,默认0,即取第一行,数据为列名行以下的数据;若数据不含列名,则设定 header = None;
index_col int, list of int, default None 用作行索引的列编号或者列名,如果给定一个序列则有多个行索引
usecols int, str, list-like, or callable default None 返回一个数据子集,该列表中的值必须可以对应到文件中的位置(数字可以对应到指定的列)或者是字符传为文件中的列名。
names array-like, default None 指定列的名字,传入一个list数据
skiprows list-like 省略指定行数的数据
skipfooter int, default 0 省略从尾部数的行数据
  • 单独参数
参数定义
sep 指定分隔符。如果不指定参数,则会尝试使用逗号分隔。参数 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?
# 使用 read_table 的时候需要注意,参数 sep 中使用的是正则表达式,因此需要对 | 进行转义变成 \| ,否则无法读取到正确的结果。
# 指定引擎为 python,否则会出现警告
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. 文件写入

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

  • csv文件 / txt文件写入

DataFrame.to_csv(path_or_buf=None, sep=’,’, na_rep=’’, float_format=None, columns=None, header=True, index=True, index_label=None, mode=‘w’, encoding=None, compression=‘infer’, quoting=None, quotechar=’"’, line_terminator=None, chunksize=None, date_format=None, doublequote=True, escapechar=None, decimal=’.’, errors=‘strict’)

  • excel文件写入

DataFrame.to_excel(excel_writer, sheet_name=‘Sheet1’, na_rep=’’, float_format=None, columns=None, header=True, index=True, index_label=None, startrow=0, startcol=0, engine=None, merge_cells=True, encoding=None, inf_rep=‘inf’, verbose=True, freeze_panes=None)

df_csv.to_csv('data/my_csv_saved.csv', index=False)
df_excel.to_excel('data/my_excel_saved.xlsx', index=False)
df_txt.to_csv('data/my_txt_saved.txt', sep='\t', index=False)

为什么要转化markdown语言,主要是为了方便保存,且易于转成其他格式,比如PDF,也能方便出版打印和交流传播

to_markdown: 表格转换为markdown语言
to_latex:可表格转换为to_latex语言
没有安装tabulate包,要先pip install tabulate

二、基本数据结构

1. Series

# Series 一般由四个部分组成,分别是序列的值 data 、索引 index 、存储类型 dtype 、序列的名字 name 。其中,索引也可以指定它的名字,默认为空。
s = pd.Series(data = [100, 'a', {
     'dic1':5}],
              index = pd.Index(['id1', 20, 'third'], name='my_idx'),
              dtype = 'object',
              name = 'my_name')
属性
.values 获取序列的值
.index 获取索引
.dtype 获取存储类型
.name 获取名字
.shape 获取序列的长度

2. DataFrame

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

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 = 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)])

属性与Series相同,转置可以用.T,这点同numpy的用法

三、常用基本函数

1. 汇总函数

函数 属性
.head() 返回表或者序列的前 n 行,默认为5
.tail() 返回表或者序列的后n行,默认为5
.info() 返回表的信息概况
.describe() 返回表中数值列对应的主要统计量

info, describe 只能实现较少信息的展示,如果想要对一份数据集进行全面且有效的观察,特别是在列较多的情况下,推荐使用 pandas-profiling 包。

df.head() #返回表或序列的前5行

		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
df.head(2) #返回表或序列的前2行

	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
df.tail(1) #返回表或序列的最后1行

	School				Grade		Name		Gender	Height	Weight	Transfer
199	Tsinghua University	Sophomore	Chunpeng Lv	Male	155.7	51.0	N
df.info() #返回表的信息概况

<class 'pandas.core.frame.DataFrame'>
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
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

2. 特征统计函数

函数 属性
.sum() 求和
.mean() 平均数
.median() 中值
.var() 方差
.std() 标准差
.max() 最大值
.min() 最小值
.quantile() 计算分位数,默认为50%分位数
.count() 计算非缺失值的个数
.idxmax() 返回最大值对应的索引
df_demo.sum() #求和

Height    29868.9
Weight    10398.0
dtype: float64
df_demo.mean() #平均数

Height    163.218033
Weight     55.015873
dtype: float64
df_demo.median() #求中值

Height    161.9
Weight     51.0
dtype: float64
df_demo.var() #计算方差

Height     74.112805
Weight    164.462513
dtype: float64
-----------------
df_demo.std() #计算标准差

Height     8.608879
Weight    12.824294
dtype: float64
df_demo.max() #计算最大值
Height    193.9
Weight     89.0
dtype: float64
-----------------
df_demo.min() #计算最小值
Height    145.4
Weight     34.0
dtype: float64
df_demo.quantile() #计算50%分位数
Height    161.9
Weight     51.0
Name: 0.5, dtype: float64
-----------------
df_demo.quantile(0.75) #计算75%分位数
Height    167.5
Weight     65.0
Name: 0.75, dtype: float64
df_demo.idxmax() #返回最大值对应的索引
Height    193
Weight      2
dtype: int64

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

df_demo.sum(axis = 1).head(3)
0    204.9
1    236.5
2    277.9
dtype: float64

3. 唯一值函数

函数 属性
.unique() 返回其唯一值组成的列表
.nunique() 返回唯一值的个数
.value_counts() 返回唯一值和其对应出现的频数
.drop_duplicates() 返回多个列组合的唯一值,关键参数是keep,默认值first表示每个组合保留第一次出现的所在行,last表示保留最后一次出现的所在行,False表示把所有重复组合所在的行剔除。
.duplicated() 返回是否为唯一值的布尔列表,其中重复元素设为True,否则为False
df['Grade'].unique() #返回其唯一值组成的列表
>>> array(['Freshman', 'Senior', 'Sophomore', 'Junior'], dtype=object)
-----------------
df['Grade'].nunique() #返回其唯一值的个数
>>> 4
df['Grade'].value_counts() #返回唯一值和其对应出现的频数
Junior       59
Senior       55
Freshman     52
Sophomore    34
Name: Grade, dtype: int64
df_demo.drop_duplicates(['Gender', 'Transfer']) #返回多个列组合的唯一值,默认keep=first,每个组合第一次出现的行

	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_demo.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_demo.drop_duplicates(['Name', 'Transfer'], keep = False).head(3) #返回不重复值

	Gender	Transfer	Name
0	Female	N			Gaopeng Yang
1	Male	N			Changqiang You
4	Male	N			Gaojuan You
df_demo.duplicated(['Gender', 'Transfer']).head() #返回是否为重复值的布尔列表
0    False
1    False
2     True
3     True
4     True
dtype: bool

4. 替换函数

一般而言,替换操作是针对某一列,即 Series 进行。

分类 函数 属性
映射替换 .replace() 可以通过字典构造,或者传入两个列表来进行替换;此外还有一种特殊的定向替换,指定method参数
映射替换 .str.replace() 字符串替换,后见Task08
映射替换 cat.codes 通过reorder_categories进行重新排序,然后再使用cat.codes来实现对整数的映射(暂时没明白与替换的关系,后改)
逻辑替换 .where(条件, 返回值) 在传入条件为False的对应行进行替换,当不指定替换值时,替换为缺失值NaN
逻辑替换 .mask() 在传入条件为True的对应行进行替换,当不指定替换值时,替换为缺失值NaN
数值替换 .round() 按照给定精度四舍五入
数值替换 .abs() 返回绝对值
数值替换 Series.clip(lower=None, upper=None, axis=None, inplace=False, *args, **kwargs) 按照给定上下界截断,前两个数分别表示上下截断边界
df['Gender'].replace({
     'Female':0, 'Male':1}).head() #通过字典构造替换
0    0
1    1
2    1
3    0
4    1
Name: Gender, dtype: int64
-----------------
df['Gender'].replace(['Female','Male'],[0,1]).head() #通过传入两个列表来进行替换
0    0
1    1
2    1
3    0
4    1
Name: Gender, dtype: int64
s.replace([1, 2], method='ffill') #一种特殊的定向替换,返回上一个未被替换的值
0    a
1    a
2    b
3    b
4    b
5    a
dtype: object
-----------------
s.replace([1, 2], method='bfill') #一种特殊的定向替换,返回下一个未被替换的值
0    a
1    b
2    b
3    a
4    a
5    a
dtype: object
s.where(s<0) #替换s>=0的值,替换为缺失值
0    -1.0
1     NaN
2     NaN
3   -50.0
dtype: float64
-----------------
s.where(s<0, 50) #替换s>=0的值,替换为50
0    -1.0
1    50.0
2    50.0
3   -50.0
dtype: float64
-----------------
s.mask(s>=0) #替换s>=0的值,替换为缺失值
0    -1.0
1     NaN
2     NaN
3   -50.0
dtype: float64
-----------------
s.mask(s>=0, 100) #替换s>=0的值,替换为100
0     -1.0
1    100.0
2    100.0
3    -50.0
dtype: float64
s.round(2) #四舍五入到两位小数
0     -1.00
1      1.23
2    100.00
3    -50.00
dtype: float64

s.abs() #返回绝对值
0      1.0000
1      1.2345
2    100.0000
3     50.0000
dtype: float64

s.clip(0, 2) #截断0-2边界外的数
0    0.0000
1    1.2345
2    2.0000
3    0.0000
dtype: float64

练一练:
在 clip 中,超过边界的只能截断为边界值,如果要把超出边界的替换为自定义的值,应当如何做?

#思考:可以使用replace代替上界和下界
a = 0
b = 2
s.clip(a, b).replace({
     a:'lower', b:'upper'})

0     lower
1    1.2345
2     upper
3     lower
dtype: object

5. 排序函数

函数 参数
.sort_values() 为值排序,默认参数 ascending=True 为升序
.sort_index() 为索引排序,需要指定索引层的名字或者层号,用参数 level 表示
df_demo = df[['Grade', 'Name', 'Height', 'Weight']].set_index(['Grade','Name'])
df_demo.sort_values('Height').head() #按照身高升序排列,显示前5行

							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_demo.sort_values('Height', ascending = False).head(3) #按照身高降序排列,显示前3行

						Height	Weight
Grade	Name		
Senior	Xiaoqiang Qin	193.9	79.0
		Mei Sun			188.9	89.0
		Gaoli Zhao		186.5	83.0
-----------------
df_demo.sort_values(['Height', 'Weight'], ascending = [False, True]).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_demo.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

6. apply方法

得益于传入自定义函数的处理, apply 的自由度很高,但这是以性能为代价的。一般而言,使用 pandas 的内置函数处理和 apply 来处理同一个任务,其速度会相差较多,因此只有在确实存在自定义需求的情境下才考虑使用 apply 。

#处理自定义函数,例如: mad 函数返回的是一个序列中偏离该序列均值的绝对值大小的均值
df_demo = df[['Height', 'Weight']]
df_demo.apply(lambda x:(x-x.mean()).abs().mean())

Height     6.707229
Weight    10.391870
dtype: float64

四、窗口对象

函数 属性
滑动窗口 rolling 参数为窗口大小window
扩张窗口 expanding Series.expanding(min_periods=1, center=None, axis=0)
指数加权窗口 ewm

1. 滑动窗口

需要注意的是窗口包含当前行所在的元素

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

0    NaN
1    3.0
2    5.0
3    7.0
4    9.0
dtype: float64
-----------------
roller.apply(lambda x:x.sum()) #等价表示
类滑窗函数 属性
.shift(n) 参数为 periods=n ,默认为1,表示取向前第 n 个元素的值
.diff(n) 参数为 periods=n ,默认为1,表示与向前第 n 个元素做差
.pct_change(n) 参数为 periods=n ,默认为1,与向前第 n 个元素相比计算增长率
s.shift(2) #取向前的第2个元素的值,即series向后移动2位

0    NaN
1    NaN
2    1.0
3    3.0
4    6.0
dtype: float64
-----------------
s.diff(2) #与向前第2个元素做差

0    NaN
1    NaN
2    5.0
3    7.0
4    9.0
dtype: float64
-----------------
s.pct_change() #与前1个元素的增长率

0         NaN
1    2.000000
2    1.000000
3    0.666667
4    0.500000
dtype: float64

n 可以为负,表示反方向的类似操作:

s.shift(-1) #取后一个元素的值

0     3.0
1     6.0
2    10.0
3    15.0
4     NaN
dtype: float64

类滑窗函数的功能可以用窗口大小为 n+1 的 rolling 方法等价代替:

s.rolling(3).apply(lambda x:list(x)[0]) #等价于s.shift(2)

练一练:
rolling 对象的默认窗口方向都是向前的,某些情况下用户需要向后的窗口,例如对1,2,3设定向后窗口为2的 sum 操作,结果为3,5,NaN,此时应该如何实现向后的滑窗操作?

s = pd.Series([1, 2, 3])
#Step1:尝试使用window参数,报错:window必须为正整数
roller = s.rolling(window = -1)
ValueError: window must be non-negative

#Step2:先试用rolling求和,再使用shift类滑窗函数
roller = s.rolling(window = 2)
roller.sum().shift(-1)

0    3.0
1    5.0
2    NaN
dtype: float64
-----------------
#也可以使用 apply 传入自定义函数
s.rolling(2).apply(lambda x:list(x)[0]+list(x)[-1]).shift(-1)

0    3.0
1    5.0
2    NaN
dtype: float64

2. 扩张窗口

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

s = pd.Series([1, 3, 6, 10])
s.expanding().sum() #累计求和

0     1.0
1     4.0
2    10.0
3    20.0
dtype: float64
类扩张函数 属性
cummax 依次给出前1,2,…,n个数的最大值
cumsum 依次给出前1,2,…,n个数的和
cumprod 依次给出前1,2,…,n个数的积
s = pd.Series([1,3,2,5,4])
s.cummax() #依次给出前1,2,...,n个数的最大值

0    1
1    3
2    3
3    5
4    5
dtype: int64
-----------------
s.cumsum() #依次给出前1,2,...,n个数的和

0     1
1     4
2     6
3    11
4    15
dtype: int64
-----------------
s.cumprod() #依次给出前1,2,...,n个数的积

0      1
1      3
2      6
3     30
4    120
dtype: int64

练一练:
cummax, cumsum, cumprod 函数是典型的类扩张窗口函数,请使用 expanding 对象依次实现它们。

s.expanding().max().astype(np.int64) #s.cummax()
s.expanding().sum().astype(np.int64) #s.cumsum()
s.expanding().apply(lambda x:x.prod()).astype(np.int64) #s.cumprod()

五、练习

Ex1:口袋妖怪数据集

现有一份口袋妖怪的数据集,下面进行一些背景说明:
#代表全国图鉴编号,不同行存在相同数字则表示为该妖怪的不同状态
妖怪具有单属性和双属性两种,对于单属性的妖怪, Type 2 为缺失值
Total, HP, Attack, Defense, Sp. Atk, Sp. Def, Speed 分别代表种族值、体力、物攻、防御、特攻、特防、速度,其中种族值为后6项之和

df = pd.read_csv('data/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
  1. 对 HP, Attack, Defense, Sp. Atk, Sp. Def, Speed 进行加总,验证是否为 Total 值。
#参数axis=1,验证结果为Total值
df_demo = df[['HP','Attack','Defense','Sp. Atk','Sp. Def','Speed']]
df_demo.sum(axis = 1).head(3)

0    318
1    405
2    525
dtype: int64
-----------------
#根据答案修改:
(df_demo.sum(axis = 1) != df['Total']).mean()
0.0
  1. 对于#重复的妖怪只保留第一条记录,解决以下问题:
    a. 求第一属性的种类数量和前三多数量对应的种类
#保留第1条数据,使用drop_duplicates,keep默认
df_dup = df.drop_duplicates(['#'])
#求第一属性的种类数量,使用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')

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

#取去重的type1和type2
df_type = df_dup.drop_duplicates(['Type 1','Type 2'])
#取行数
df_type.shape[0]
>>> 143

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

#1.求出所有的组合,使用列表推导式
L_full = [i+' '+j for i in df['Type 1'].unique() for j in df['Type 2'].unique()]
>>> TypeError: can only concatenate str (not "float") to str
-----------------
df['Type 1'].unique()
>>> array(['Grass', 'Fire', 'Water', 'Bug', 'Normal', 'Poison', 'Electric',
       'Ground', 'Fairy', 'Fighting', 'Psychic', 'Rock', 'Ghost', 'Ice',
       'Dragon', 'Dark', 'Steel', 'Flying'], dtype=object)
#把numpy数组转化为列表:tolist(参考答案)
L_full = [i+' '+j for i in df['Type 1'].unique() for j in (df['Type 1'].unique().tolist() + [' '])]
#2. 列出表中组合,注意type2中缺失值
L_now = [i+' '+j for i, j in zip(df_dup['Type 1'], df_dup['Type 2'].replace(np.nan, ' '))]
#3. 对比取差异(参考答案)
res = set(L_full).difference(set(L_now))
res

{
     'Bug Bug',
 'Bug Dark',
 'Bug Dragon',
 ...
 'Water Normal',
 'Water Water'}
-----------------
len(res)
>>> 199
  1. 按照下述要求,构造 Series :
    a. 取出物攻,超过120的替换为 high ,不足50的替换为 low ,否则设为 mid
Attack = df['Attack']
Attack.clip(50, 120).replace({
     50:'low',120:'high'}).mask((Attack>=50)&(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
#参考答案给了另外一种方法
df['Attack'].mask(df['Attack']>120, 'high').mask(df['Attack']<50, 'low').mask((50<=df['Attack'])&(df['Attack']<=120), 'mid')

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

#使用replace
df['Type 1'].replace({
     i:str.upper(i) for i in df['Type 1'].unique()})

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
#使用apply
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

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

#离差的概念:max(abs(x-median))
df_ability = df[['HP','Attack','Defense','Sp. Atk','Sp. Def','Speed']]
df['Deviation'] = df_ability.apply(lambda x:np.max((x-x.median()).abs()), axis=1) #求离差
#添加到 df 并倒序:sort_value
df.sort_values('Deviation', ascending=False)

	#	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
...

Ex2:指数加权窗口

  1. 作为扩张窗口的 ewm 窗口
    在扩张窗口中,用户可以使用各类函数进行历史的累计指标统计,但这些内置的统计函数往往把窗口中的所有元素赋予了同样的权重。事实上,可以给出不同的权重来赋给窗口中的元素,指数加权窗口就是这样一种特殊的扩张窗口。
    其中,最重要的参数是 alpha,它决定了默认情况下的窗口权重为 w i = ( 1 − α ) i , i ∈ { 0 , 1 , . . . , t } w_i = (1 - \alpha)^i, i\in \{0, 1, ..., t\} wi=(1α)i,i{ 0,1,...,t},其中 i=t 表示当前元素, i=0 表示序列的第一个元素。
    从权重公式可以看出,离开当前值越远则权重越小,若记原序列为 x,更新后的当前元素为 y t y_t yt,此时通过加权公式归一化后可知:
    编程实践(Pandas) Task02_第1张图片
    对于 Series 而言,可以用 ewm 对象如下计算指数平滑后的序列:
np.random.seed(0)
s = pd.Series(np.random.randint(-1,2,30).cumsum())
s.head()

0   -1
1   -1
2   -2
3   -2
4   -2
dtype: int32
s.ewm(alpha=0.2).mean().head()

0   -1.000000
1   -1.000000
2   -1.409836
3   -1.609756
4   -1.725845
dtype: float64

请用 expanding 窗口实现。

#自定义函数(参考答案)
def ewm_func(x, alpha=0.2):
    win = (1-alpha)**np.arange(x.shape[0])[::-1]
    res = (win*x).sum()/win.sum()
    return res
s.expanding().apply(ewm_func)

0    -1.000000
1    -1.000000
2    -1.409836
3    -1.609756
...
29   -4.314107
dtype: float64
  1. 作为滑动窗口的 ewm 窗口
    从第1问中可以看到, ewm 作为一种扩张窗口的特例,只能从序列的第一个元素开始加权。现在希望给定一个限制窗口 n ,只对包含自身的最近的 n 个元素作为窗口进行滑动加权平滑。请根据滑窗函数,给出新的 w i w_i wi y t y_t yt 的更新公式,并通过 rolling 窗口实现这一功能。
s.rolling(window=4).apply(ewm_func)

0          NaN
1          NaN
2          NaN
3    -1.609756
4    -1.826558
...
29   -4.783198
dtype: float64

参考文献

  1. https://blog.csdn.net/brucewong0516/article/details/79096633?ops_request_misc=%25257B%252522request%25255Fid%252522%25253A%252522160828465316780274033842%252522%25252C%252522scm%252522%25253A%25252220140713.130102334…%252522%25257D&request_id=160828465316780274033842&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_click~default-1-79096633.first_rank_v2_pc_rank_v29&utm_term=read_excel
  2. https://blog.csdn.net/sinat_35562946/article/details/81058221?ops_request_misc=%25257B%252522request%25255Fid%252522%25253A%252522160828485016780310131225%252522%25252C%252522scm%252522%25253A%25252220140713.130102334…%252522%25257D&request_id=160828485016780310131225&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_click~default-1-81058221.first_rank_v2_pc_rank_v29&utm_term=read_csv%20%E5%8F%82%E6%95%B0
  3. https://blog.csdn.net/lwgkzl/article/details/80988126
  4. https://blog.csdn.net/dontla/article/details/103068208

你可能感兴趣的:(datawhale,python,pandas)