mar*_*ion 409 python vectorization dataframe pandas
你能告诉我什么时候使用这些矢量化方法和基本的例子吗?
我看到这map
是一种Series
方法,而其余的是DataFrame
方法.我对此感到困惑apply
和applymap
方法.为什么我们有两种方法将函数应用于DataFrame?再一次,说明用法的简单例子会很棒!
jer*_*dha 484
直接来自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
Run Code Online (Sandbox Code Playgroud)
许多最常见的数组统计信息(如sum和mean)都是DataFrame方法,因此使用apply不是必需的.
也可以使用元素化的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
Run Code Online (Sandbox Code Playgroud)
名称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
Run Code Online (Sandbox Code Playgroud)
总结一下,apply
在DataFrame的行/列基础上工作,在DataFrame applymap
上以map
元素方式工作,并在Series上以元素方式工作.
Mar*_*ese 61
这些答案中提供了很多信息,但我正在添加自己的信息,以清楚地总结哪些方法在数组方面与元素方式相关.jeremiahbuddha大多是这样做的,但没有提到Series.apply.我没有代表评论.
DataFrame.apply
一次对整行或列进行操作.
DataFrame.applymap
,Series.apply
并且Series.map
在一个元素上运行.
在Series.apply
和的功能之间存在很多重叠Series.map
,这意味着在大多数情况下任何一个都可以工作.他们确实有一些细微的差别,其中一些在osa的答案中讨论过.
osa*_*osa 36
Apply可以从一个系列中创建一个DataFrame ; 然而,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
Run Code Online (Sandbox Code Playgroud)
此外,如果我有一个副作用的功能,如"连接到Web服务器",我可能apply
只是为了清楚起见.
series.apply(download_file_for_every_element)
Run Code Online (Sandbox Code Playgroud)
Map
不仅可以使用函数,还可以使用字典或其他系列.假设你想操纵排列.
采取
1 2 3 4 5
2 1 4 5 3
Run Code Online (Sandbox Code Playgroud)
这种排列的平方是
1 2 3 4 5
1 2 5 3 4
Run Code Online (Sandbox Code Playgroud)
你可以用它来计算它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
Run Code Online (Sandbox Code Playgroud)
cs9*_*s95 35
map
,applymap
和:上下文问题ap
ply
第一个主要区别:定义
map
仅在系列上定义applymap
仅在DataFrames上定义apply
两者都定义第二个主要区别:输入参数
map
接受dict
S, Series
,或可调用applymap
并且apply
只接受可调用第三大区别:行为
map
对于系列是元素applymap
对于DataFrames是元素apply
也可以逐元素工作,但适用于更复杂的操作和聚合。行为和返回值取决于函数。四主要的区别(最重要的):用例
map
用于将值从一个域映射到另一个域,因此针对性能进行了优化(例如df['A'].map({1:'a', 2:'b', 3:'c'})
)applymap
适用于跨多个行/列的元素转换(例如df[['A', 'B', 'C']].applymap(str.strip)
)apply
用于应用无法向量化的任何功能(例如df['sentences'].apply(nltk.sent_tokenize)
)脚注
map
通过字典/系列时,将基于该字典/系列中的键映射元素。缺少的值将在输出中记录为NaN。
applymap
在最新版本中,已针对某些操作进行了优化。您会发现applymap
比apply
某些情况下要快一些。我的建议是对它们都进行测试,并使用更好的方法。
map
针对元素映射和转换进行了优化。涉及字典或系列的操作将使熊猫能够使用更快的代码路径来获得更好的性能。Series.apply
返回用于汇总操作的标量,否则返回Series。同样适用于DataFrame.apply
。需要注意的是apply
,当某些NumPy的功能,如所谓的也有FastPaths的mean
,sum
等等。
use*_*752 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
Run Code Online (Sandbox Code Playgroud)
只是想指出,因为我有点挣扎
def f(x):
if x < 0:
x = 0
elif x > 100000:
x = 100000
return x
df.applymap(f)
df.describe()
Run Code Online (Sandbox Code Playgroud)
df = df.applymap(f)
df.describe()
Run Code Online (Sandbox Code Playgroud)
可能最简单的解释apply和applymap之间的区别:
apply将整列作为参数,然后将结果分配给此列
applymap将单独的单元格值作为参数,并将结果分配回此单元格.
注意如果apply返回单个值,则在赋值后将使用此值而不是列,最终将只有一行而不是矩阵.
小智 6
基于cs95的答案
map
仅在系列上定义applymap
仅在 DataFrame 上定义apply
在 BOTH 上定义举一些例子
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
Run Code Online (Sandbox Code Playgroud)
为了提供额外的上下文和直觉,这里有一个明确且具体的差异示例。
假设您有如下所示的功能。(此标签函数将根据您作为参数 (x) 提供的阈值,将值任意分割为“高”和“低”。)
def label(element, x):
if element > x:
return 'High'
else:
return 'Low'
Run Code Online (Sandbox Code Playgroud)
在此示例中,假设我们的数据框有一列包含随机数。
如果您尝试使用 map 映射标签函数:
df['ColumnName'].map(label, x = 0.8)
Run Code Online (Sandbox Code Playgroud)
您将出现以下错误:
TypeError: map() got an unexpected keyword argument 'x'
Run Code Online (Sandbox Code Playgroud)
现在采用相同的函数并使用 apply,您会发现它有效:
df['ColumnName'].apply(label, x=0.8)
Run Code Online (Sandbox Code Playgroud)
Series.apply()可以按元素获取附加参数,而Series.map()方法将返回错误。
现在,如果您尝试同时将相同的函数应用于数据框中的多个列,则使用DataFrame.applymap() 。
df[['ColumnName','ColumnName2','ColumnName3','ColumnName4']].applymap(label)
Run Code Online (Sandbox Code Playgroud)
最后,您还可以在数据帧上使用 apply() 方法,但 DataFrame.apply() 方法具有不同的功能。df.apply() 方法不是按元素应用函数,而是沿轴(按列或按行)应用函数。当我们创建一个与 df.apply() 一起使用的函数时,我们将其设置为接受一系列,最常见的是一列。
这是一个例子:
df.apply(pd.value_counts)
Run Code Online (Sandbox Code Playgroud)
当我们将 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)
Run Code Online (Sandbox Code Playgroud)
这将导致以下错误:
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')
Run Code Online (Sandbox Code Playgroud)
一般来说,我们应该只在向量化函数不存在时使用 apply() 方法。回想一下,pandas 使用矢量化(即一次对整个序列应用操作的过程)来优化性能。当我们使用 apply() 方法时,我们实际上是在循环行,因此向量化方法可以比 apply() 方法更快地执行等效任务。
以下是您不想使用任何类型的 apply/map 方法重新创建的已存在的向量化函数的一些示例: