对于pandas DataFrame

时间:2017-09-14 04:42:38

标签: python pandas dataframe

虽然DataFrame上的applymap函数在元素方面运行,但transform函数似乎实现了相同的功能,除了声称返回类似索引的DataFrame。

问题:

  1. 是否有任何用例,其中一个有效,另一个没有?
  2. 一个人的表现比另一个好吗?
  3. 文档中陈述的索引类似DataFrame是什么?

4 个答案:

答案 0 :(得分:8)

不同的用例。比较它们时,同时调出applyagg非常有用。

设置

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中的一种不起作用?

好的。以下是一些示例:

1)applymap Vs 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

2)应用Vs变换

applytransform可以互换,只要您在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前缀):

  • gb.apply
  • gb.transform
  • gb.filter
  • gb.agg
  • gb.count
  • gb.comsum
  • gb.fillna
  • ...

希望这会有所帮助:)

答案 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