有许多方法可以在Pandas中创建新列(我可能在我的示例中遗漏了一些,所以请告诉我是否还有其他内容,我将在此处包含)并且我想知道何时是使用每种方法的最佳时间.显然,某些方法在某些情况下与其他方法相比更好,但我想从整体观点来评估效率,可读性和实用性.
我主要关注的是前三个,但其他方式只是为了表明它可能采用不同的方法.这是您的示例数据框:
df = pd.DataFrame({'a':[1,2,3],'b':[4,5,6]})
最常见的方法是命名一个新列,例如df [‘c’]并使用apply:
df['c'] = df['a'].apply(lambda x: x * 2)
df
a b c
0 1 4 2
1 2 5 4
2 3 6 6
使用assign可以完成同样的事情:
df = df.assign(c = lambda x: x['a'] * 2)
df
a b c
0 1 4 2
1 2 5 4
2 3 6 6
通过@roganjosh更新:
df['c'] = df['a'] * 2
df
a b c
0 1 4 2
1 2 5 4
2 3 6 6
使用地图(绝对不如申请效率高):
df['c'] = df['a'].map(lambda x: x * 2)
df
a b c
0 1 4 2
1 2 5 4
2 3 6 6
创建一个新的pd.series然后concat将其带入数据帧:
c = pd.Series(df['a'] * 2).rename("c")
df = pd.concat([df,c], axis = 1)
df
a b c
0 1 4 2
1 2 5 4
2 3 6 6
使用join:
df.join(c)
a b c
0 1 4 2
1 2 5 4
2 3 6 6
解决方法:
简短回答:矢量化调用(df [‘c’] = 2 * df [‘a’])几乎总是在速度和可读性上都获胜.有关在性能方面可用作选项“层次结构”的内容,请参阅this答案.
一般来说,如果你有一个for i in或lambda存在于Pandas操作中的某个地方,这(有时)意味着结果计算调用Python代码而不是Pandas的Cython库依赖于矢量化操作的优化C代码. (对于依赖于NumPy ufuncs的基础.values的操作也是如此.)
至于.assign(),在注释中正确指出这会创建一个副本,而你可以查看df [‘c’] = 2 * df [‘a’]等同于设置字典键/值.前者也需要两倍的时间,虽然这可能有点像苹果到橙色,因为一个操作返回一个DataFrame,而另一个操作只是分配一个列.
>>> %timeit df.assign(c=df['a'] * 2)
498 µs ± 15.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
>>> %timeit -r 7 -n 1000 df['c'] = df['a'] * 2
239 µs ± 22.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
至于.map():通常你会看到这个,顾名思义,你想为一个系列提供一个映射(虽然它可以传递一个函数,如你的问题所示).这并不意味着它不具备高性能,它只是在我看到的情况下被用作专门的方法:
>>> df['a'].map(dict(enumerate('xyz', 1)))
0 x
1 y
2 z
Name: a, dtype: object
至于.apply():为答案注入一点意见,我认为在可能的情况下使用矢量化更为惯用.您可以在module where .apply()
is defined的代码中看到:因为您传递的是lambda而不是NumPy ufunc,最终调用的是技术上的Cython函数map_infer
,但它仍然执行您在系列的每个成员上传递的任何函数df [‘a’],一次一个.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。