一个python例子,明白apply--applymap--map区别,以及where函数用法
首先,这些函数在Series和DataFrame中都能用(除了applymap())
我们来针对一道题目作为例子,来看看这些函数如何使用:
这道题目的例子来源于我看了另外一篇相关的优快云博客,这里附上他的链接:
https://blog.youkuaiyun.com/weixin_39791387/article/details/81487549
题目如下:
df = pd.DataFrame({'change_type' : [1,1,0,0,1,0],
'price' : [100, 90, 50, 120, 150, 200],
'changed' : [10,8,4,11,14,10]})
change_type = 1 表示涨价 0表示降价
price 表示经过涨价或者降价之后的价格,也就是 --> 现价
changed 表示 涨了多少 或者 降了多少 是一个绝对值
针对上述表,求:涨降价的比例
首先,先写出计算公式:
涨价比例 = 涨了多少 / 原价
降价的比例 = 降了多少 / 原价
import numpy as np
import pandas as pd
df = pd.DataFrame({'change_type' : [1,1,0,0,1,0],
'price' : [100, 90, 50, 120, 150, 200],
'changed' : [10,8,4,11,14,10]})
print(df)
print('****************************************************')
#涨价比例
df_up = df['changed'].div(df['price'].add(df['changed']))
#降价比例
df_down = df['changed'].div(df['price'].sub(df['changed']))
当然你可以直接用 +-*/ 来替换上述的除法div()、加法add()、减法sub()
因为np,pd包的目的就是为了避免写if、for循环,所以我的思路是:用where函数来解决上面的问题
df['scale'] = pd.where(df['change_type'] ==1,df['changed'].div(df['price'].add(df['changed'])),df['changed'].div(df['price'].sub(df['changed'])))
我想这样在 df 新增一列 ‘scale’ 作为比例的结果。
我以为的逻辑是:如果为1,进行涨价比例计算,将结果填入scale列
如果为0,进行降价比例计算,将结果填入scale列
这样就能直接得到结果了!!!
但是!很遗憾,where并没有帮我们达到这样的要求,这样写会报错! 但是我又不想写if,
查了好多资料,都没有提到关键性的一点。
不好意思,我脑残了。。通过对着python代码的报错情况不断分析!!!终于领悟了为什么!
where函数在pd和np中的运用还是有区别的:
pd中:
是针对单个元素,进行条件判断,然后进行 --> 值替换,
在这条件判断中用到的'所有数据元素'都会被结果值替换
np中:
针对单个列(Series),进行where可以达到我们上述所期望的要求!
啊哈哈,虽然能解决了,但是同时能深刻理解where也不错~~
现在我想清楚了一个解决方案了!
下面写上解决思路:
1、首先在df原表添加一列scale列,你可以用empty()、zero()、arrange()、
还是手动输入都行,里面的值随便填,因为后续操作要将结果替换进去,
这里的目的只是为了创建出与'scale列'对应的一列的空间,。
2、对scale列中的数据,根据条件赋值。
3、OK问题得到完美解决!!!~下面附上执行结果图。
df['scale']=np.arange(6)
df['scale'] = np.where(df['change_type'] == 1, df_up,df_down)
//当然这个条件判断 df['']== 1 有点多此一举,因为0就是False,有值就是True
//可以改为df['scale'] = np.where(df['change_type'], df_up,df_down)
print(df)
apply()
apply()官方文档
在pd中使用
apply()函数的功能是将一个自定义函数作用于DataFrame的行或者列
(其他骚操作,详细参数,请点击上述官方文档,看官方例子,我这里给出一般用法)
错误案例:
def original_price():
return np.where(df['change_type'], df_up, df_down)
df['scale'] = np.arrange(6)
df['scale'] = df.apply(original_price())
print(df)
这里我定义了一个函数,然后将函数写入apply参数中,
但是报错了,不知道为什么,希望懂得大佬能留言指导一下,谢谢!
我自己的解决方案是:
def original_price():
return np.where(df['change_type'], df_up, df_down)
df['scale']=np.arange(6)
df['scale'] = df.apply(lambda x: np.where(df['change_type'] == 1, df_up,df_down))
print(df)
添加一个lambda,写成lambda表达式就能解决原因,
但是这样写还不如直接写成:
df['scale'] = df.apply(lambda x: np.where(df['change_type'], df_up, df_down))
这样更符合lambda表达式的初衷,(里面的形参x可以不填,因为没用到)
但是查阅了lambda表达式资料,我也没明白如何解决上述错误的原因,
只看到lambda是一个匿名函数,它可以当做变量使用,在这里应该就是这个意思,
希望懂得的大佬能指点一下!
所以综上,
我自己理解的apply()方法的一般用法,
是在里面传入一个lambda表达式,
这样绝对不会报错!
还有重要的一点,要留意当心 apply中的 axis参数,
因为实际处理结果和我们认为的相反,可以多试试去注意一下!
在np中使用:
np中没有apply这个方法,
但是你输入np.a的时候,会自动跳出来一个 np.apply_along_axis方法。
没错!
我仔细看了一下里面的形参,需要传入3个参数:
func:填lambda表达式绝对不会报错
axis=轴(填0或者‘index’表示行
填1或者‘columns’表示列)
arr=填你要进行操作的Series对象
解决方案:
df02 = np.apply_along_axis(lambda x:np.where(df['change_type'],df_up,df_down),axis=0,arr=df['change_type'])
print(df02)
细看了下,还有个np.apply_over_axex()方法,
它针对的主要是高维数组,如(3维)数组上的操作,
官方文档:
https://docs.scipy.org/doc/numpy-1.12.0/reference/generated/numpy.apply_over_axes.html
看不懂的话可以看下面这个优快云大佬的链接:
https://blog.csdn.net/a_31415926/article/details/50491211
map()
map()菜鸟教程
map()和reduce()用法和原理
map() 是python自带的函数,也就是我们常说的高阶函数,但它在DataFrame中可以直接使用 .map() 后缀的方式调用,由于只能直接对序列元素的操作,所以必须对DataFrame的某列 (只针对于列) 应用操作。
在pd中使用:
解决方案:
df03 = df['change_type'].map(lambda x:np.where(df['change_type'],df_up,df_down))[0]
print(df03)
因为map操作的是序列,所以是对df['change_type']这一列进行.map()
在np中使用:
直接对np数组对象.map()就行了
比如:
我先拷贝一列DataFrame列赋值给变量data01,这样data01就是一个Series对象
然后对Series对象进行操作
当然这对于解决这道题目多此一举,这里只是演示np如何用map()
data01 = df['change_type']
data02 = df['price']
data03 = df['changed']
df04 = data01.map(lambda x:np.where(data01,df_up,df_down))[0]
print(df04)
applymap()
applymap()官方文档
只能在pd中使用:
因为Series对象没有applymap()方法
解决方案:
df05 = df.applymap(lambda x:np.where(df['change_type'],df_up,df_down))['change_type'][0]
print(df05)
最后来看一下3种方法在DataFrame种的区别演示
原始数据:
apply():
df01 = df.apply(lambda x:np.where(df['change_type'],df_up,df_down))
三列数据一致,原因是where方法不恰当运用导致的,这里可以忽略。
体会一下3种方法,导致的结果形式即可。
map():
df03 = df['change_type'].map(lambda x:np.where(df['change_type'],df_up,df_down))
print(df03)
返回的是一个Series,也就是一列,一列当中的每一行结果都重复。
可以df[ ‘xxx’ ].map(xxxxx)[0] 通过索引取值获得一行,作为结果值。
applymap():
df05 = df.applymap(lambda x:np.where(df['change_type'],df_up,df_down))
print(df05)
返回的是一个DataFrame,也就是有三列,
因为applymap()不恰当使用,导致了change_type列 和 price列 和 changed列 的值都一样了。
大致意会一下三种方法返回的形式即可
总结
apply()和map()和applymap()
三种方法的本质,其实是对什么type的对象操作,返回对应type的结果。
apply()官方文档
apply_along_axis官方文档
apply_over_axes()官方文档
(详细参数,请点击上述官方文档,看官方例子,我这里给出一般用法总结)
apply():
pandas中的方法:
DataFrame操作,返回DataFrame
numpy中无此方法:
但是有类似的2个方法,apply_along_axis和apply_over_axes
还有重要的一点,要留意当心 apply中的 axis参数,
因为实际处理结果和我们认为的相反,可以多试试去注意一下!
map():
python自带的函数(高阶函数):
只对序列进行操作,在pandas和numpy中可以理解为只对Series操作
applymap():
pandas中的方法:
对DataFrame操作,返回DataFrame
where()方法
where()官方文档
官方文档还是不理解的话,看这篇博客试试
另外一篇
1、 where在pandas和numpy中的用法 小区别:
pandas中:
//条件为真不做修改,条件为假替换成相应值
//false_value不填默认为np.nan,即显示:NaN(Not a number)
df.where(conditon,false_value)
//mask()方法和where作用相反,条件为真做修改,条件为假不修改
//true_value不填默认为np.nan,即显示:NaN(Not a number)
df.mask(condition,true_value)
numpy中:
//根据条件判断,如果为True替换成相应值,如果为False替换成相应值
arr.where(condition,true_value,false_value)
2、 where函数在pd和np中的运用的 注意点:
pd中:
是针对单个元素,进行条件判断,然后进行 --> 值替换,
在这条件判断中用到的(所有数据元素)都会被结果值替换。
np中:
针对单个要显示判断结果的列(Series),进行where方法判断,
此时条件判断中用到的(所有数据元素)都不会被修改。
lambda表达式(匿名函数):
lambda表达式详解
lambda表达式用的时候需要的一个注意点
匿名函数,可以当参数调用
、、哭了。。。。。。。我这个菜B花了一下午,终于把这篇博客写完了。。。现在脑子一片浆糊QAQ。。。。。。。。。。