不同的使用情况。在进行比较时,提及 apply
和 agg
会很有帮助。
设置
np.random.seed([3,1415])
df = pd.DataFrame(np.random.randint(10, size=(6, 4)), columns=list('ABCD'))
df
A B C D
0 0 2 7 3
1 8 7 0 6
2 8 6 0 2
3 0 4 9 7
4 3 2 4 3
5 3 6 7 7
pd.DataFrame.applymap
该函数接受一个函数作为参数,将该函数应用于每个单元格中的值,并用结果替换单元格的值,最终返回一个新的数据帧。
df.applymap(lambda x: str(x) * x)
A B C D
0 22 7777777 333
1 88888888 7777777 666666
2 88888888 666666 22
3 4444 999999999 7777777
4 333 22 4444 333
5 333 666666 7777777 7777777
pd.DataFrame.agg
'mean'
或'max'
。这两个函数都会从一组数据中获取一个标量并返回。df.agg('mean')
A 3.666667
B 4.500000
C 4.500000
D 4.666667
dtype: float64
或者
df.agg(['mean', 'std', 'first', 'min'])
A B C D
mean 3.666667 4.500000 4.500000 4.666667
std 3.614784 2.167948 3.834058 2.250926
min 0.000000 2.000000 0.000000 2.000000
pd.DataFrame.transform
该函数需要传入一个应用于列并返回相同大小列的函数。
df.transform(lambda x: x / x.std())
A B C D
0 0.000000 0.922531 1.825742 1.332785
1 2.213133 3.228859 0.000000 2.665570
2 2.213133 2.767594 0.000000 0.888523
3 0.000000 1.845062 2.347382 3.109832
4 0.829925 0.922531 1.043281 1.332785
5 0.829925 2.767594 1.825742 3.109832
pd.DataFrame.apply
Pandas试图判断apply
操作是否在减少所操作的列的维度(即聚合)或者是否将该列转换为大小相等的另一列。当它确定了这一点后,会将其余的操作作为聚合或转换过程来执行。
df.apply('mean')
A 3.666667
B 4.500000
C 4.500000
D 4.666667
dtype: float64
或者
df.apply(lambda x: (x - x.mean()) / x.std())
A B C D
0 -1.014353 -1.153164 0.652051 -0.740436
1 1.198781 1.153164 -1.173691 0.592349
2 1.198781 0.691898 -1.173691 -1.184698
3 -1.014353 -0.230633 1.173691 1.036611
4 -0.184428 -1.153164 -0.130410 -0.740436
5 -0.184428 0.691898 0.652051 1.036611
“文档中提到的
.transform()
返回一个与输入长度相同的 DataFrame,使索引标签保持一致。”
这意味着 .transform()
将一个函数应用于 DataFrame 中的每个值(或组,在使用groupby
前)并返回另一个与输入长度相同的 DataFrame。强调一下:它在输出中保留了输入的索引标签。
是否存在其中一个方法能用而另一个方法不能用的情况?
当然。以下是一些例子:
applymap
对 DataFrame 中的所有元素执行操作,因此不能对 Series 执行 applymap
:
df['Quantity'].transform(lambda x: x+10) # successful
df['Quantity'].apply(lambda x: x+10) # successful
df['Quantity'].applymap(lambda x: x+10) # gives AttributeError: 'Series' object has no attribute 'applymap'
# unless you cast it to DataFrame:
pd.DataFrame(df['Quantity']).applymap(lambda x: x+10) # successful
另一个重要的区别是,尽管.applymap()
进行逐元素操作,.transform()
可以执行分组操作,这在下一部分中提到。
此外,applymap()
不能由groupby()
前置执行。
apply
和transform
可以相互替换,只要它们作用于DataFrame的列(s)。这里有一个简单的例子:
# imagine the following DataFrame
df = pd.DataFrame({'Label': ['A', 'B', 'C', 'A', 'C'],
'Values': [0,1,2,3,4],
'Quantity': [5,6,7,8,9]}, index = list('VWXYZ'))
Label Quantity Values
---------------------------------
V A 5 0
W B 6 1
X C 7 2
Y A 8 3
Z C 9 4
df.loc[:, ['Quantity', 'Values']].apply(lambda x: x+10)
df.loc[:, ['Quantity', 'Values']].transform(lambda x: x+10)
# both of them give the following same result:
Quantity Values
-------------------------
V 15 10
W 16 11
X 17 12
Y 18 13
Z 19 14
groupby
操作时。例如:label_grouping = df.groupby('Label')
label_grouping.apply(lambda x: x.mean())
# output:
Quantity Values
Label
-----------------------
A 6.5 1.5
B 6.0 1.0
C 8.0 3.0
label_grouping.transform(lambda x: x.mean())
# see how `transform` could manage to keeps the input index labels in the output
# output:
Quantity Values
------------------------
V 6.5 1.5
W 6.0 1.0
X 8.0 3.0
Y 6.5 1.5
Z 8.0 3.0
transform
如何保留输入 DataFrame 的索引;因此为了更好地利用这一独特的功能,下面的简短示例尝试说明如何通过计算每个产品代表的订单总额的百分比来从输入和输出之间的索引对齐中受益:df_sales = pd.DataFrame({'OrderID': [1001,1001,1001,1002,1002],
'Product': ['p1','p2','p3','p1','p4'],
'Quantity': [30,20,70,160,40]})
OrderID Product Quantity
-----------------------------------
0 1001 p1 30
1 1001 p2 20
2 1001 p3 70
3 1002 p1 160
4 1002 p4 40
df_sales['total_per_order'] = df_sales.groupby(['OrderID'])['Quantity'].transform(lambda x: x.sum())
df_sales['pct_of_order'] = df_sales['Quantity'] / df_sales['total_per_order']
OrderID Product Quantity total_per_order pct_of_order
----------------------------------------------------------------------
0 1001 p1 30 120 0.250000
1 1001 p2 20 120 0.166667
2 1001 p3 70 120 0.583333
3 1002 p1 160 200 0.800000
4 1002 p4 40 200 0.200000
强烈建议您访问以下链接以获取更详细的示例:https://pbpython.com/pandas_transform.html
许多聚合函数已直接内置到groupby
对象中,以减少您的输入。具体而言,一些常见函数(以gb为前缀)可供使用:
希望这可以帮助您 :)
> df = pd.DataFrame([['europe', 'france', 68],
> ['europe', 'russia', 144],
> ['asia', 'china', 1398]],
> columns=['continent', 'country', 'population'])
> df
continent country population
0 europe france 68
1 europe russia 144
2 asia china 1398
applymap
> df[['country', 'population']].set_index('country')
.applymap(lambda x: 'big' if x > 100 else 'small')
country
france small
russia big
china big
> df.groupby(['continent'], sort=False)['population'].applymap(max)
AttributeError: 'SeriesGroupBy' object has no attribute 'applymap'
转换
> df[['country', 'population']].set_index('country')
.transform(lambda x: 'big' if x > 100 else 'small')
ValueError: The truth value of a Series is ambiguous.
> df.groupby(['continent'], sort=False)['population'].transform(max)
0 144
1 144
2 1398
Name: population, dtype: int64
> df[df.groupby(['continent'], sort=False)['population'].transform(max)
== df['population']]
continent country population
1 europe russia 144
2 asia china 1398