【Python】Pandas中的宝藏函数-transform()
Pandas具有很多强⼤的功能,transform就是其中之⼀,利⽤它可以⾼效地汇总数据且不改变数据⾏数,transform是⼀种什么数据操作?如果熟悉SQL的窗⼝函数,就⾮常容易理解了,该函数的核⼼功能是,既计算了统计值,⼜保留了明细数据。为了更好地理解transform和agg的不同,下⾯从实际的应⽤场景出发进⾏对⽐。
aggregation会返回数据的缩减版本,⽽transformation能返回完整数据的某⼀变换版本供我们重组。这样的transformation,输出的形状和输⼊⼀致。⼀个常见的例⼦是通过减去分组平均值来居中数据。
#数据构造
data = pd.DataFrame(
{"company":['百度', '阿⾥', '百度', '阿⾥', '百度', '腾讯', '腾讯', '阿⾥', '腾讯', '阿⾥'],
"salary":[43000, 24000, 40000, 39000, 8000, 47000, 25000, 16000, 21000, 38000],
"age":[25, 34, 49, 42, 28, 23, 45, 21, 34, 29]})
data
company  salary  age
0      百度  43000  25
groupby是什么函数1      阿⾥  24000  34
2      百度  40000  49
3      阿⾥  39000  42
4      百度    8000  28
5      腾讯  47000  23
6      腾讯  25000  45
7      阿⾥  16000  21
8      腾讯  21000  34
9      阿⾥  38000  29
1、transform作⽤于Series
1)单个变换函数
当transform作⽤于单列Series时较为简单 ,对salary列进⾏transform变换我们可以传⼊任意的⾮聚合类函数,⽐如对⼯资列对数化
import pandas as pd
import numpy  as np
# 对⼯资对数化
data['salary'].transform(np.log)
0    10.668955
1    10.085809
2    10.596635
3    10.571317
4    8.987197
5    10.757903
6    10.126631
7    9.680344
8    9.952278
9    10.545341
Name: salary, dtype: float64
除了内置函数,还可以传⼊lambda函数
# lambda函数
data['salary'].transform(lambda s: s+1)
0    43001
1    24001
2    40001
3    39001
4    8001
5    47001
6    25001
7    16001
8    21001
9    38001
Name: salary, dtype: int64
2)多个变换函数
也可以传⼊包含多个变换函数的列表来⼀⼝⽓计算出多列结果:
data['salary'].transform([np.log, lambda s: s+1, np.sqrt])
log  <lambda>        sqrt
0  10.668955    43001  207.364414
1  10.085809    24001  154.919334
2  10.596635    40001  200.000000
3  10.571317    39001  197.484177
4  8.987197      8001  89.442719
5  10.757903    47001  216.794834
6  10.126631    25001  158.113883
7  9.680344    16001  126.491106
8  9.952278    21001  144.913767
9  10.545341    38001  194.935887
⽽⼜因为transform传⼊的函数,在执⾏运算时接收的输⼊参数是对应的整列数据,所以我们可以利⽤这个特点实现诸如数据标准化、归⼀化等需要依赖样本整体统计特征的变换过程:
# 利⽤transform进⾏数据标准化
data['salary'].transform(lambda s: (s - s.mean()) / s.std())
0    0.991038
1  -0.468630
2    0.760564
3    0.683739
4  -1.697825
5    1.298337
6  -0.391806
7  -1.083228
8  -0.699104
9    0.606915
Name: salary, dtype: float64
2、 transform作⽤于DataFrame
当transform作⽤于整个DataFrame时,实际上就是将传⼊的所有变换函数作⽤到每⼀列中:
data.loc[:,'salary':'age'].transform(lambda s:(an()) /s.std())
salary      age
0  0.991038 -0.832050
1 -0.468630  0.104006
2  0.760564  1.664101
3  0.683739  0.936057
4 -1.69782
5 -0.520031
5  1.298337 -1.040063
6 -0.391806  1.248075
7 -1.083228 -1.248075
8 -0.699104  0.104006
9  0.606915 -0.416025
⽽当传⼊多个变换函数时,对应的返回结果格式类似agg中的机制,会⽣成MultiIndex格式的字段名
data.loc[:, 'salary': 'age'].transform([np.log, lambda s: s+1])
salary                age
log <lambda>      log <lambda>
0  10.668955    43001  3.218876      26
1  10.085809    24001  3.526361      35
2  10.596635    40001  3.891820      50
3  10.571317    39001  3.737670      43
4  8.987197    8001  3.33220
5      29
5  10.757903    47001  3.135494      24
6  10.126631    25001  3.806662      46
7  9.680344    16001  3.044522      22
8  9.952278    21001  3.526361      35
9  10.545341    38001  3.367296      30
⽽且由于作⽤的是DataFrame,还可以利⽤字典以键值对的形式,⼀⼝⽓为每⼀列配置单个或多个变换函数:
(data.loc[:, 'salary': 'age']
.transform({'age': lambda s: (s - s.mean()) / s.std(),
'salary': [np.log, np.sqrt]}))
age    salary
<lambda>        log        sqrt
0 -0.832050  10.668955  207.364414
1  0.104006  10.085809  154.919334
2  1.664101  10.596635  200.000000
3  0.936057  10.571317  197.484177
4 -0.520031  8.987197  89.442719
5 -1.040063  10.757903  216.794834
6  1.248075  10.126631  158.113883
7 -1.248075  9.680344  126.491106
8  0.104006  9.952278  144.913767
9 -0.416025  10.545341  194.935887
3、transform作⽤于groupby分组后
在原来的数据中,我们知道了如何求不同公司的平均薪⽔,假如需要在原数据集中新增⼀列salary_mean,代表该公司的平均薪⽔,该怎么实现呢?
data['salary_mean'] = upby('company')[['salary']].transform('mean')
data
company  salary  age  salary_mean
0      百度  43000  25  30333.333333
1      阿⾥  24000  34  29250.000000
2      百度  40000  49  30333.333333
3      阿⾥  39000  42  29250.000000
4      百度    8000  28  30333.333333
5      腾讯  47000  23  31000.000000
6      腾讯  25000  45  31000.000000
7      阿⾥  16000  21  29250.000000
8      腾讯  21000  34  31000.000000
9      阿⾥  38000  29  29250.000000
通过上⾯的数据可以看出,利⽤transform输出,既得到了统计数据,形状也没有变化。
当然,也可对多个数据列进⾏计算
salary  age
0  30333.333333  34.0
1  29250.000000  31.5
2  30333.33333
3  34.0
3  29250.000000  31.5
4  30333.333333  34.0
5  31000.000000  34.0
6  31000.000000  34.0
7  29250.000000  31.5
8  31000.000000  34.0
9  29250.000000  31.5
我们也可以⽤map函数实现类似的功能,但是稍微复杂点,但是有助于我们理解transform的含义。
avg_dict = upby('company')['salary'].mean().to_dict()
avg_dict#得到了⼀个平均⼯资的字典
{'百度': 30333.333333333332, '腾讯': 31000.0, '阿⾥': 29250.0}
#利⽤map函数,将得到的字典映射到对应的列
data['salary_mean'] = data['company'].map(avg_dict)
data
company  salary  age  salary_mean
0      百度  43000  25  30333.333333
1      阿⾥  24000  34  29250.000000
2      百度  40000  49  30333.333333
3      阿⾥  39000  42  29250.000000
4      百度    8000  28  30333.333333
5      腾讯  47000  23  31000.000000
6      腾讯  25000  45  31000.000000
7      阿⾥  16000  21  29250.000000
8      腾讯  21000  34  31000.000000
9      阿⾥  38000  29  29250.000000
以图解的⽅式来看看进⾏groupby后transform的实现过程(公司列包含ABC,salary列为每个员⼯的⼯资明细):
上图中的⼤⽅框是transform和agg 所不⼀样的地⽅,对agg⽽⾔,会计算并聚合得到 A,B,C 公司对
应的均值并直接返回,每个公司⼀条数据,但对transform⽽⾔,则会对每⼀条数据求得相应的结果,同⼀组内的样本会有相同的值,组内求完均值后会按照原索引的顺序返回结果
往期精彩回顾
适合初学者⼊门⼈⼯智能的路线及资料下载机器学习及深度学习笔记等资料打印机器学习在线⼿册深度学习笔记专辑《统计学习⽅法》的代码复现专辑
AI基础下载机器学习的数学基础专辑黄海⼴⽼师《机器学习课程》课件合集
本站qq851320808,加⼊请扫码:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。