在逛Kaggle的时候发现了一篇不错的Pandas技巧,我将挑选一些有用的并外加一些自己的想法分享给大家。
本系列虽基础但带仍有一些奇怪操作,粗略扫一遍,您或将发现一些您需要的技巧。
纸上得来终觉浅,绝知此事要躬行,所谓的熟练使用Pandas是建立在您大致了解每个函数功能上,希望本系列能给您带来些许收获。
本篇所涉及知识点:
- map、apply、applymap
- groupby
- MultiIndex DataFrame
- 统计函数、累计函数
- agg、transform、filter
map、apply和applymap
先总结一下:
- map()适用于Series,相当于将Series中的每个元素作为参数带入指定函数,注意是Series中的每个元素。
- apply()适用于DataFrame的行或者列,将整个行列作为参数带入指定函数,注意是DataFrame的行或列,即整个Series。
- applymap()适用于DataFrame中的每个元素,注意是DataFrame中的每个元素。
map
Series.map(self,arg,na_action)
作用于一个Series上,DataFrame的一行或者一列都是Series。
map()最主要的用途是实现以下两个功能:
- 字典替换
- 简单的有参函数(有且仅有一个参数,其实就是Series里的每个元素了)
df = pd.DataFrame([['小王', 'm', 80], ['小红', 'f', 90], ['小明', 'x', 85], [
'小林', np.nan, 83], ], columns=['student', 'sex', 'score'])
df
student sex score
0 小王 m 80
1 小红 f 90
2 小明 x 85
3 小林 NaN 83
使用dict对Series进行映射替换。如果Series中的值并没有在给定字典中出现,那该值会被替换为np.nan。
下面案例中我想把sex='m’替换为"男",sex='f’替换为"女",小明的sex='x’我并没有在字典中给出映射,所以map()后直接被替换为np.nan。
my_dict = {
'm': '男', 'f': '女'}
df['dict'] = df['sex'].map(my_dict)
df
student sex score dict
0 小王 m 80 男
1 小红 f 90 女
2 小明 x 85 NaN
3 小林 NaN 83 NaN
如果对于未给定的键我们也想统一替换,那就要在字典中设置默认值,接下来教大家如何设置字典默认值。
from collections import defaultdict
def ret():
"""
describe:因为defaultdict接受一个工厂函数,所以咱们直接创建一个函数,返回Unknown
return :str
"""
return 'Unknown'
# 生成一个新的dict,使用defaultdict函数并传入我们创建的工厂函数
# 当然你也可以填入其他的数据类型,具体类型及对应默认值如下:
# int->0,set->set(),str->'',list->[]
my_hasdefault_dict = defaultdict(ret)
# 将之前的dict再传入新的含有默认值的dict
my_dict = {
'm': '男', 'f': '女'}
for k, v in my_dict.items():
my_hasdefault_dict[k] = v
# 因为小林的sex=np.nan没有在给定字典中出现,所以也替换成了默认值
df['hasdefault_dict'] = df['sex'].map(my_hasdefault_dict)
# 在map中设置na_action='ignore'时就会忽略np.nan,不进行任何操作
df['ignore_na'] = df['sex'].map(my_hasdefault_dict, na_action='ignore')
df
student sex score dict hasdefault_dict ignore_na
0 小王 m 80 男 男 男
1 小红 f 90 女 女 女
2 小明 x 85 NaN Unknown Unknown
3 小林 NaN 83 NaN Unknown NaN
map()可以应用一些简单的自定义函数。
def my_cut(x):
"""
descrieb:对成绩分桶
return :str
"""
if x >= 90:
return 'score>=90'
if 85 <= x < 90:
return '85<=score<90'
else:
return 'score<85'
# map里面只要写入函数名就可以,不用括号
df['my_cut'] = df['score'].map(my_cut)
# 上面的判断比较简单,所以我们可以改写成lambda的形式
# lambda的格式是 lambda x:结果1 if 条件1 else 结果2 if 条件2 else 结果3
df['cut_lambda'] = df['score'].map(
lambda x: 'score>=90' if x >= 90 else '85<=score<90' if 85 <= x < 90 else 'score<85')
# 当然上面只是为了演示map,其实用Pandas自带的cut更方便
# right=True是右闭区间,right=False是左闭区间
df['cut'] = pd.cut(df['score'], bins=[-np.inf, 85, 90, np.inf],
labels=['score<85', '85<=score<90', 'score>=90'], right=False)
df
student sex score my_cut cut_lambda cut
0 小王 m 80 score<85 score<85 score<85
1 小红 f 90 score>=90 score>=90 score>=90
2 小明 x 85 85<=score<90 85<=score<90 85<=score<90
3 小林 NaN