Pandas中map,applymap和apply方法之间的区别

时间:2013-11-05 20:20:14

标签: python pandas dataframe vectorization

您能告诉我何时将这些矢量化方法与基本示例一起使用?

我发现mapSeries方法,其余是DataFrame方法。我对applyapplymap方法感到困惑。为什么我们有两种方法将函数应用于DataFrame?再次,说明用法的简单例子会很棒!

10 个答案:

答案 0 :(得分:425)

直接来自Wes McKinney的Python for Data Analysis书,pg。 132(我强烈推荐这本书):

  

另一个常见的操作是将1D数组上的函数应用于每个列或行。 DataFrame的apply方法就是这样做的:

In [116]: frame = DataFrame(np.random.randn(4, 3), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])

In [117]: frame
Out[117]: 
               b         d         e
Utah   -0.029638  1.081563  1.280300
Ohio    0.647747  0.831136 -1.549481
Texas   0.513416 -0.884417  0.195343
Oregon -0.485454 -0.477388 -0.309548

In [118]: f = lambda x: x.max() - x.min()

In [119]: frame.apply(f)
Out[119]: 
b    1.133201
d    1.965980
e    2.829781
dtype: float64
  

许多最常见的数组统计信息(如sum和mean)都是DataFrame方法,       所以使用申请是没有必要的。

     

也可以使用元素化的Python函数。假设您想要从帧中的每个浮点值计算格式化字符串。您可以使用applymap执行此操作:

In [120]: format = lambda x: '%.2f' % x

In [121]: frame.applymap(format)
Out[121]: 
            b      d      e
Utah    -0.03   1.08   1.28
Ohio     0.65   0.83  -1.55
Texas    0.51  -0.88   0.20
Oregon  -0.49  -0.48  -0.31
  

名称applymap的原因是Series有一个map方法来应用逐元素函数:

In [122]: frame['e'].map(format)
Out[122]: 
Utah       1.28
Ohio      -1.55
Texas      0.20
Oregon    -0.31
Name: e, dtype: object

总结一下,apply适用于DataFrame的行/列,applymap在DataFrame上以元素方式工作,而map在系列上以元素方式工作。< / p>

答案 1 :(得分:33)

Series中添加其他答案,还有mapapply

应用可以从系列中制作数据框;然而,map只会在另一个系列的每个单元格中放置一个系列,这可能不是你想要的。

In [40]: p=pd.Series([1,2,3])
In [41]: p
Out[31]:
0    1
1    2
2    3
dtype: int64

In [42]: p.apply(lambda x: pd.Series([x, x]))
Out[42]: 
   0  1
0  1  1
1  2  2
2  3  3

In [43]: p.map(lambda x: pd.Series([x, x]))
Out[43]: 
0    0    1
1    1
dtype: int64
1    0    2
1    2
dtype: int64
2    0    3
1    3
dtype: int64
dtype: object

此外,如果我有一个带副作用的功能,例如&#34;连接到网络服务器&#34;,我可能只是为了清晰起见而使用apply

series.apply(download_file_for_every_element) 

Map不仅可以使用某个功能,还可以使用字典或其他系列。我们假设您要操纵permutations

1 2 3 4 5
2 1 4 5 3

这种排列的平方是

1 2 3 4 5
1 2 5 3 4

您可以使用map计算它。不确定是否记录了自我应用程序,但它在0.15.1中有效。

In [39]: p=pd.Series([1,0,3,4,2])

In [40]: p.map(p)
Out[40]: 
0    0
1    1
2    4
3    2
4    3
dtype: int64

答案 2 :(得分:19)

@jeremiahbuddha提到apply适用于行/列,而applymap是按元素工作的。但似乎你仍然可以使用申请元素计算....

    frame.apply(np.sqrt)
    Out[102]: 
                   b         d         e
    Utah         NaN  1.435159       NaN
    Ohio    1.098164  0.510594  0.729748
    Texas        NaN  0.456436  0.697337
    Oregon  0.359079       NaN       NaN

    frame.applymap(np.sqrt)
    Out[103]: 
                   b         d         e
    Utah         NaN  1.435159       NaN
    Ohio    1.098164  0.510594  0.729748
    Texas        NaN  0.456436  0.697337
    Oregon  0.359079       NaN       NaN

答案 3 :(得分:9)

只是想指出,因为我有点挣扎了

def f(x):
    if x < 0:
        x = 0
    elif x > 100000:
        x = 100000
    return x

df.applymap(f)
df.describe()

这不会修改数据帧本身,必须重新分配

df = df.applymap(f)
df.describe()

答案 4 :(得分:7)

可能最简单的解释了apply和applymap之间的区别:

apply 将整个列作为参数,然后将结果分配给此列

applymap 将单独的单元格值作为参数,并将结果分配回此单元格。

NB如果apply返回单个值,则在赋值后将使用此值而不是列,并且最终将只有一行而不是矩阵。

答案 5 :(得分:3)

根据cs95

的答案
  • map仅在系列上定义
  • applymap仅在DataFrames上定义
  • apply都在

举一些例子

In [3]: frame = pd.DataFrame(np.random.randn(4, 3), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])

In [4]: frame
Out[4]:
            b         d         e
Utah    0.129885 -0.475957 -0.207679
Ohio   -2.978331 -1.015918  0.784675
Texas  -0.256689 -0.226366  2.262588
Oregon  2.605526  1.139105 -0.927518

In [5]: myformat=lambda x: f'{x:.2f}'

In [6]: frame.d.map(myformat)
Out[6]:
Utah      -0.48
Ohio      -1.02
Texas     -0.23
Oregon     1.14
Name: d, dtype: object

In [7]: frame.d.apply(myformat)
Out[7]:
Utah      -0.48
Ohio      -1.02
Texas     -0.23
Oregon     1.14
Name: d, dtype: object

In [8]: frame.applymap(myformat)
Out[8]:
            b      d      e
Utah     0.13  -0.48  -0.21
Ohio    -2.98  -1.02   0.78
Texas   -0.26  -0.23   2.26
Oregon   2.61   1.14  -0.93

In [9]: frame.apply(lambda x: x.apply(myformat))
Out[9]:
            b      d      e
Utah     0.13  -0.48  -0.21
Ohio    -2.98  -1.02   0.78
Texas   -0.26  -0.23   2.26
Oregon   2.61   1.14  -0.93


In [10]: myfunc=lambda x: x**2

In [11]: frame.applymap(myfunc)
Out[11]:
            b         d         e
Utah    0.016870  0.226535  0.043131
Ohio    8.870453  1.032089  0.615714
Texas   0.065889  0.051242  5.119305
Oregon  6.788766  1.297560  0.860289

In [12]: frame.apply(myfunc)
Out[12]:
            b         d         e
Utah    0.016870  0.226535  0.043131
Ohio    8.870453  1.032089  0.615714
Texas   0.065889  0.051242  5.119305
Oregon  6.788766  1.297560  0.860289

答案 6 :(得分:2)

我的理解:

从功能的角度来看:

如果函数包含需要在列/行中进行比较的变量,请使用 apply

例如:lambda x: x.max()-x.mean()

如果要将函数应用于每个元素:

1&GT;如果找到了列/行,请使用apply

2 - ;如果适用于整个数据框,请使用applymap

majority = lambda x : x > 17
df2['legal_drinker'] = df2['age'].apply(majority)

def times10(x):
  if type(x) is int:
    x *= 10 
  return x
df2.applymap(times10)

答案 7 :(得分:1)

比较mapapplymapap ply:上下文很重要

主要区别:定义

  • map仅在系列上定义
  • applymap仅在DataFrames上定义
  • apply都是在两者上定义的

第二个主要区别:输入参数

  • map接受dictSeries或可呼叫
  • applymapapply仅接受可调用项

第三大区别:行为

  • map是Series的元素方式
  • applymap对于DataFrames是元素化的
  • apply也可以逐元素地工作,但适用于更复杂的操作和聚合。行为和返回值取决于函数。

第四大区别(最重要的区别):使用案例

  • map用于将值从一个域映射到另一个域,因此针对性能进行了优化
  • applymap适用于跨多个行/列的元素式转换
  • apply用于应用无法向量化的任何功能

总结

enter image description here

  

脚注

     
      
  1. map传递字典/系列时,将基于该字典/系列中的键来映射元素。缺少的值将记录为   输出中的NaN。
  2.   最新版本中的
  3. applymap已针对某些操作进行了优化。您会发现applymap的速度比apply快一点   一些案例。我的建议是同时测试它们并使用任何可行的方法   更好。

  4.   
  5. map已针对元素映射和转换进行了优化。涉及字典或系列的操作将使熊猫能够   使用更快的代码路径以获得更好的性能。

  6.   
  7. Series.apply返回用于汇总操作的标量,否则返回Series。对于DataFrame.apply同样。请注意,apply还具有   当使用某些NumPy函数(例如mean)调用快速路径时,   sum
  8.   

答案 8 :(得分:1)

只是为了额外的上下文和直觉,这里有一个明确而具体的差异示例。

假设您有如下所示的函数。 ( 此标签函数将根据您作为参数 (x) 提供的阈值,将值任意拆分为“高”和“低”。 )

def label(element, x):
    if element > x:
        return 'High'
    else:
        return 'Low'

在这个例子中,假设我们的数据帧有一列随机数。

Df with one column that has random numbers

如果您尝试使用 map 映射标签函数:

df['ColumnName'].map(label, x = 0.8)

你会得到以下错误:

TypeError: map() got an unexpected keyword argument 'x'

现在使用相同的函数并使用apply,你会看到它起作用了:

df['ColumnName'].apply(label, x=0.8)

Series.apply() 可以按元素接受额外的参数,而 Series.map() 方法将返回错误。

现在,如果您尝试将相同的函数同时应用于数据框中的多个列,则使用 DataFrame.applymap()

df[['ColumnName','ColumnName2','ColumnName3','ColumnName4']].applymap(label)

最后,您还可以对数据帧使用 apply() 方法,但 DataFrame.apply() 方法具有不同的功能。 df.apply() 方法不是按元素应用函数,而是沿轴(按列或按行)应用函数。当我们创建一个与 df.apply() 一起使用的函数时,我们将它设置为接受一个系列,最常见的是一个列。

这是一个例子:

df.apply(pd.value_counts)

当我们将 pd.value_counts 函数应用于数据框时,它计算了所有列的值计数。

注意,这很重要,当我们使用 df.apply() 方法转换多列时。这是唯一可能的,因为 pd.value_counts 函数对一个系列进行操作。如果我们尝试使用 df.apply() 方法将一个以元素方式工作的函数应用于多列,我们会得到一个错误:

例如:

def label(element):
    if element > 1:
        return 'High'
    else:
        return 'Low'

df[['ColumnName','ColumnName2','ColumnName3','ColumnName4']].apply(label)

这将导致以下错误:

ValueError: ('The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().', u'occurred at index Economy')

一般来说,我们应该只在不存在向量化函数时才使用 apply() 方法。回想一下,pandas 使用向量化,即一次对整个系列应用操作的过程来优化性能。当我们使用 apply() 方法时,我们实际上是在遍历行,因此矢量化方法可以比 apply() 方法更快地执行相同的任务。

apply, applymap, map summarization

以下是一些已经存在的向量化函数示例,您不想使用任何类型的应用/映射方法重新创建它们:

  1. Series.str.split() 拆分系列中的每个元素
  2. Series.str.strip() 从系列中的每个字符串中去除空格。
  3. Series.str.lower() 将系列中的字符串转换为小写。
  4. Series.str.upper() 将系列中的字符串转换为大写。
  5. Series.str.get() 检索系列中每个元素的第 i 个元素。
  6. Series.str.replace() 用另一个字符串替换系列中的正则表达式或字符串
  7. Series.str.cat() 连接一个系列中的字符串。
  8. Series.str.extract() 从与正则表达式模式匹配的系列中提取子字符串。

答案 9 :(得分:0)

FOMO:

以下示例显示了applyapplymap应用于DataFrame的情况。

map函数仅适用于Series。您不能在DataFrame上应用map

要记住的事情是,apply可以做任何事情 applymap,但是apply具有 eXtra 选项。

X因子选项为:axisresult_type,其中result_type仅在axis=1(对于列)时有效。

df = DataFrame(1, columns=list('abc'),
                  index=list('1234'))
print(df)

f = lambda x: np.log(x)
print(df.applymap(f)) # apply to the whole dataframe
print(np.log(df)) # applied to the whole dataframe
print(df.applymap(np.sum)) # reducing can be applied for rows only

# apply can take different options (vs. applymap cannot)
print(df.apply(f)) # same as applymap
print(df.apply(sum, axis=1))  # reducing example
print(df.apply(np.log, axis=1)) # cannot reduce
print(df.apply(lambda x: [1, 2, 3], axis=1, result_type='expand')) # expand result

请注意,Series map函数不应与Python map函数混淆。

第一个应用于Series,以映射值,第二个应用于迭代对象的每个项目。


最后不要将数据框apply方法与groupby apply方法混淆。