练习
Ex1:口袋妖怪数据集
现有一份口袋妖怪的数据集,下面进行一些背景说明:
-
#
代表全国图鉴编号,不同行存在相同数字则表示为该妖怪的不同状态 -
妖怪具有单属性和双属性两种,对于单属性的妖怪,
Type 2
为缺失值 -
Total, HP, Attack, Defense, Sp. Atk, Sp. Def, Speed
分别代表种族值、体力、物攻、防御、特攻、特防、速度,其中种族值为后6项之和
In [116]: df = pd.read_csv('data/pokemon.csv')
In [117]: df.head(3)
Out[117]:
# 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
值。 -
对于
#
重复的妖怪只保留第一条记录,解决以下问题:
- 求第一属性的种类数量和前三多数量对应的种类
- 求第一属性和第二属性的组合种类
- 求尚未出现过的属性组合
- 按照下述要求,构造
Series
:
- 取出物攻,超过120的替换为
high
,不足50的替换为low
,否则设为mid
- 取出第一属性,分别用
replace
和apply
替换所有字母为大写 - 求每个妖怪六项能力的离差,即所有能力中偏离中位数最大的值,添加到
df
并从大到小排序
答案:
# 1
res = df['Total'] != df[['HP', 'Attack', 'Defense', 'Sp. Atk', 'Sp. Def', 'Speed']].sum(axis=1)
res.sum()
# 2.a
df1 = df.drop_duplicates(['#'])
print(df1['Type 1'].value_counts()[:3].index)
# 2.b
attr_dup = df1.drop_duplicates(['Type 1', 'Type 2'])
print(attr_dup)
len(attr_dup)
Index(['Water', 'Normal', 'Grass'], dtype='object')
# 2.c 没想到高效方法
# 3.a
def f(x):
if x > 120:
return 'high'
elif x >= 50:
return 'mid'
else:
return 'low'
print(df['Attack'].apply(f)[:5])
# 3.b
print(df['Type 1'].apply(lambda x: x.upper()))
# 3.c
df1 = df[['HP', 'Attack', 'Defense', 'Sp. Atk', 'Sp. Def', 'Speed']]
df['Max_bias'] = (df1 - df1.median()).abs().max(axis=1)
df.sort_values('Max_bias', ascending=False).head()
参考答案:
# 2.c 参考答案
# 保证单属性的类型的存在
L_full = [i+' '+j for i in df['Type 1'].unique() for j in (
df['Type 1'].unique().tolist() + [''])]
L_part = [i+' '+j for i, j in zip(df['Type 1'], df['Type 2'].replace(np.nan, ''))]
res = set(L_full).difference(set(L_part))
len(res)
# 3.a参考答案
# pandas内置函数效率高于apply
df['Attack'].mask(df['Attack']>120, 'high'
).mask(df['Attack']<50, 'low').mask((50<=df['Attack']
)&(df['Attack']<=120), 'mid').head()
# 3.b参考答案
# pandas内置函数效率高于apply
df['Type 1'].replace({i: i.upper() for i in df['Type 1'].unique()}).head()
# 3.c参考答案
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()
Ex2:指数加权窗口
- 作为扩张窗口的
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=t
i=t表示当前元素,
i
=
0
i=0
i=0表示序列的第一个元素。
从权重公式可以看出,离开当前值越远则权重越小,若记原序列为
x
x
x,更新后的当前元素为
y
t
y_t
yt,此时通过加权公式归一化后可知:
对于Series
而言,可以用ewm
对象如下计算指数平滑后的序列:
In [118]: np.random.seed(0)
In [119]: s = pd.Series(np.random.randint(-1,2,30).cumsum())
In [120]: s.head()
Out[120]:
0 -1
1 -1
2 -2
3 -2
4 -2
dtype: int32
In [121]: s.ewm(alpha=0.2).mean().head()
Out[121]:
0 -1.000000
1 -1.000000
2 -1.409836
3 -1.609756
4 -1.725845
dtype: float64
请用expanding
窗口实现。
- 作为滑动窗口的
ewm
窗口
从第1问中可以看到,ewm
作为一种扩张窗口的特例,只能从序列的第一个元素开始加权。现在希望给定一个限制窗口n
,只对包含自身最近的n
个窗口进行滑动加权平滑。请根据滑窗函数,给出新的wi
与yt
的更新公式,并通过rolling
窗口实现这一功能。
参考答案:
# 1
def ewm_func(x, alpha=0.2):
# Series与np.array可直接做运算(结果为Seires)
win = (1-alpha)**np.arange(x.shape[0])[::-1]
res = (win*x).sum()/win.sum()
return res
# 对窗口使用apply方法
s.expanding().apply(ewm_func).head()
# 2
s.rolling(window=4).apply(ewm_func).head()
心得体会
- 这次时间比较紧张,在DDL前两小时才完成任务,练习2自己没有充分思考,学习质量相对低一些,下次一定提前完成!