pandas transform小结

Posted bitcarmanlee

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pandas transform小结相关的知识,希望对你有一定的参考价值。

1.transform用法

pandas中的transform是个非常强大的函数。transform可以调用一个函数,在每个组上生成一个相似的索引数据帧,并返回一个数据帧,该数据帧的索引与原始对象的索引相同,并填充转换后的值。核心是在每个组上生成一个相似的索引数据帧,这个就奠定了transform的强大之处,后面很多使用场合中我们都可以慢慢来体会

2.使用transform进行数据标准化

import pandas as pd

category = ['a', 'a', 'a', 'b', 'b', 'c']
score = [80, 85, 90, 70, 76, 64]
data = pd.DataFrame('category': category, 'score': score)

data['std'] = data['score'].transform(lambda s: (s - s.mean()) / s.std())
print(data)
  category  score       std
0        a     80  0.260785
1        a     85  0.782354
2        a     90  1.303924
3        b     70 -0.782354
4        b     76 -0.156471
5        c     64 -1.408238

上面的代码就是对score列进行标准化操作。

从上面的操作我们可以看出transform的如下几个特征:
1.transform中的函数,执行运算时接收的输入参数是相应的一列数据,因此可以使用诸如mean, std等整体统计指标。
2.最后返回的结果,带上了原始对象的索引,可以很方便的与原始数据进行拼接返回。

3.transform一次传入多个方法

transform还可以一次性传入多个方法,一并进行计算。

import pandas as pd
import numpy as np

category = ['a', 'a', 'a', 'b', 'b', 'c']
score = [80, 85, 90, 70, 76, 64]
data = pd.DataFrame('category': category, 'score': score)

data[['sqrt', 'std']] = data['score'].transform([np.sqrt, lambda s: (s - s.mean()) / s.std()])
print(data)
  category  score      sqrt       std
0        a     80  8.944272  0.260785
1        a     85  9.219544  0.782354
2        a     90  9.486833  1.303924
3        b     70  8.366600 -0.782354
4        b     76  8.717798 -0.156471
5        c     64  8.000000 -1.408238

4.与groupby配合使用

transform经常与groupby配合使用。下面我们通过一个例子来深刻理解在每个组上生成一个相似的索引数据帧。

我们还是选用计算占比的例子

department = ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C']
group = ['g1', 'g1', 'g2', 'g3', 'g3', 'g4', 'g5', 'g5']
score = [100, 200, 300, 100, 100, 300, 200, 120]
data = pd.DataFrame('department': department, 'group': group, 'score': score)

下面我们想计算每个group元素在各自department中的占比。

先尝试如下写法

data['rate'] = data['score'] / data.groupby('department')['score'].sum()
print(data)

结果如下

  department group  score        r1  rate
0          A    g1    100  0.070423   NaN
1          A    g1    200  0.140845   NaN
2          A    g2    300  0.211268   NaN
3          B    g3    100  0.070423   NaN
4          B    g3    100  0.070423   NaN
5          B    g4    300  0.211268   NaN
6          C    g5    200  0.140845   NaN
7          C    g5    120  0.084507   NaN

很明显不是我们想要的结果。问题出在哪里?

print(data.groupby('department')['score'].sum())
print(type(data.groupby('department')['score'].sum()))

如果运行上面两行代码,

department
A    600
B    500
C    320
Name: score, dtype: int64
<class 'pandas.core.series.Series'>

很明显上面的结果,与原数据行数不一致,索引也无法对齐,得到的结果都是NaN。
transform就可以完美解决上面的问题。

print(data.groupby('department')['score'].transform('sum'))
print(type(data.groupby('department')['score'].transform('sum')))
0    600
1    600
2    600
3    500
4    500
5    500
6    320
7    320
Name: score, dtype: int64
<class 'pandas.core.series.Series'>

可以看出来,transform保留了与原来数据相同的索引。因此我们求占比,只需要在前面的基础上稍作改动:

data['rate'] = data['score'] / data.groupby('department')['score'].transform('sum')
print(data)

最后输出结果就是我们希望的:

  department group  score      rate
0          A    g1    100  0.166667
1          A    g1    200  0.333333
2          A    g2    300  0.500000
3          B    g3    100  0.200000
4          B    g3    100  0.200000
5          B    g4    300  0.600000
6          C    g5    200  0.625000
7          C    g5    120  0.375000

如果不使用transform,过程就会曲折很多

score_total = data.groupby('department')['score'].sum().rename('score_total').reset_index()
data = data.merge(score_total, on='department')
data['rate'] = data['score'] / data['score_total']

需要先新建一列score_total,然后将score_total与原数据根据department列进行merge(join)操作,最后再计算占比。
相比较之下,transform就简洁方便太多了

以上是关于pandas transform小结的主要内容,如果未能解决你的问题,请参考以下文章

Unity相机跟随小结

仿射变换(CGAffineTransform)使用小结

Attention Is All You Need(Transformer)原理小结

pandas中apply和transform方法的性能比较

pandas小结

Pandas的apply, map, transform介绍和性能测试