虽然DataFrame上的applymap
函数在元素方面运行,但transform
函数似乎实现了相同的功能,除了声称返回类似索引的DataFrame。
问题:
答案 0 :(得分:8)
不同的用例。比较它们时,同时调出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
答案 1 :(得分:1)
我是新熊猫,并试图找到同一问题的答案。我在Pandas网站(https://pandas.pydata.org/pandas-docs/stable/basics.html)
上找到了这个因为并非所有函数都可以被矢量化(接受NumPy数组和 返回另一个数组或值),方法applymap()在DataFrame上 和类似的map()on Series接受任何Python函数 单值并返回单个值。
我认为传递给transform的函数应该被矢量化,整个系列将作为参数传递给这些函数。传递给map(和applymap)的函数不需要进行矢量化,并且每个元素都将传递给函数,因为map会迭代该函数。
答案 2 :(得分:1)
.transform()
的含义是返回文档中所述的类似索引的DataFrame?
这意味着.transform()
将一个函数应用于DataFrame中的每个值(或一个组,其后是groupby
),并返回另一个与输入长度相同的DataFrame,因此要强调:将输入索引标签保留在输出中。
有没有一种用例,其中applymap / transform中的一种不起作用?
好的。以下是一些示例:
由于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列上执行即可。这是一个简单的示例:
# 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索引;因此,为了更好地利用此独占功能,以下简短示例尝试通过计算每种产品的订单总数百分比来阐明如何从transform
操作的输入和输出之间的索引对齐中受益代表:
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前缀):
希望这会有所帮助:)
答案 3 :(得分:0)
> 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
应用地图
> 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