excel | csv | txt | |
---|---|---|---|
文件读取 | pd.read_excel() | pd.read_csv() | pd.read_table() |
数据写入 | to_excel() | to_csv() | to_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
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
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?
最常用的操作是把 index 设置为 False ,特别当索引没有特殊意义的时候,这样的行为能把索引在保存的时候去除。
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’)
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
# 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 | 获取序列的长度 |
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的用法
函数 | 属性 |
---|---|
.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
函数 | 属性 |
---|---|
.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
函数 | 属性 |
---|---|
.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
一般而言,替换操作是针对某一列,即 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
函数 | 参数 |
---|---|
.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
得益于传入自定义函数的处理, 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 |
需要注意的是窗口包含当前行所在的元素
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
扩张窗口又称累计窗口,可以理解为一个动态长度的窗口,其窗口的大小就是从序列开始处到具体操作的对应位置,其使用的聚合函数会作用于这些逐步扩张的窗口上。
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()
现有一份口袋妖怪的数据集,下面进行一些背景说明:
#
代表全国图鉴编号,不同行存在相同数字则表示为该妖怪的不同状态
妖怪具有单属性和双属性两种,对于单属性的妖怪, 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
- 对 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
- 对于
#
重复的妖怪只保留第一条记录,解决以下问题:
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
- 按照下述要求,构造 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
...
- 作为扩张窗口的
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,此时通过加权公式归一化后可知:
对于 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
- 作为滑动窗口的 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