例如,假设我有以下带有n
行的dataframe:
N = 10
A_list = np.random.randint(1, 100, N)
B_list = np.random.randint(1, 100, N)
df = pd.DataFrame({'A': A_list, 'B': B_list})
df.head()
# A B
# 0 78 50
# 1 23 91
# 2 55 62
# 3 82 64
# 4 99 80
进一步假设我希望创建一个新列,作为两列a
和B
的函数。在下面的示例中,我将使用一个简单的函数divide()
。要应用该函数,可以使用df.apply()
或np.vectorize()
:
def divide(a, b):
if b == 0:
return 0.0
return float(a)/b
df['result'] = df.apply(lambda row: divide(row['A'], row['B']), axis=1)
df['result2'] = np.vectorize(divide)(df['A'], df['B'])
df.head()
# A B result result2
# 0 78 50 1.560000 1.560000
# 1 23 91 0.252747 0.252747
# 2 55 62 0.887097 0.887097
# 3 82 64 1.281250 1.281250
# 4 99 80 1.237500 1.237500
如果我将n
的实际大小增加到100万或更多,那么我会发现np.vectorize()
比df.apply()
快25倍或更多。
import pandas as pd
import numpy as np
import time
def divide(a, b):
if b == 0:
return 0.0
return float(a)/b
for N in [1000, 10000, 100000, 1000000, 10000000]:
print ''
A_list = np.random.randint(1, 100, N)
B_list = np.random.randint(1, 100, N)
df = pd.DataFrame({'A': A_list, 'B': B_list})
start_epoch_sec = int(time.time())
df['result'] = df.apply(lambda row: divide(row['A'], row['B']), axis=1)
end_epoch_sec = int(time.time())
result_apply = end_epoch_sec - start_epoch_sec
start_epoch_sec = int(time.time())
df['result2'] = np.vectorize(divide)(df['A'], df['B'])
end_epoch_sec = int(time.time())
result_vectorize = end_epoch_sec - start_epoch_sec
print 'N=%d, df.apply: %d sec, np.vectorize: %d sec' % \
(N, result_apply, result_vectorize)
# Make sure results from df.apply and np.vectorize match.
assert(df['result'].equals(df['result2']))
N=1000, df.apply: 0 sec, np.vectorize: 0 sec
N=10000, df.apply: 1 sec, np.vectorize: 0 sec
N=100000, df.apply: 2 sec, np.vectorize: 0 sec
N=1000000, df.apply: 24 sec, np.vectorize: 1 sec
N=10000000, df.apply: 262 sec, np.vectorize: 4 sec
我如何使用Pandas的‘应用’功能多列?
如何将函数应用于Pandas数据帧的两列
我首先要说的是,Pandas和NumPy数组的强大之处来自于对数值数组的html" target="_blank">高性能矢量化计算。1矢量化计算的全部意义是通过将计算移到高度优化的C代码和利用连续的内存块来避免Python级别的循环。2
现在我们可以看看一些计时。下面是所有Python级循环,它们生成包含相同值的pd.series
、np.ndarray
或list
对象。为了分配给数据帧中的一个系列,结果是可比较的。
# Python 3.6.5, NumPy 1.14.3, Pandas 0.23.0
np.random.seed(0)
N = 10**5
%timeit list(map(divide, df['A'], df['B'])) # 43.9 ms
%timeit np.vectorize(divide)(df['A'], df['B']) # 48.1 ms
%timeit [divide(a, b) for a, b in zip(df['A'], df['B'])] # 49.4 ms
%timeit [divide(a, b) for a, b in df[['A', 'B']].itertuples(index=False)] # 112 ms
%timeit df.apply(lambda row: divide(*row), axis=1, raw=True) # 760 ms
%timeit df.apply(lambda row: divide(row['A'], row['B']), axis=1) # 4.83 s
%timeit [divide(row['A'], row['B']) for _, row in df[['A', 'B']].iterrows()] # 11.6 s
一些外卖:
def foo(row):
print(type(row))
assert False # because you only need to see this once
df.apply(lambda row: foo(row), axis=1)
输出:
。创建、传递和查询Pandas series对象相对于NumPy数组会带来很大的开销。这并不奇怪:Pandas系列包含了相当多的支架来保存索引、值、属性等。
使用raw=true
再次执行相同的练习,您将看到
。这一切在文档中都有描述,但看到它更有说服力。
np.vectorize
的文档有以下注意事项:
vectorized函数对输入数组的连续元组求值pyfunc
,与python map函数一样,不同的是它使用了numpy的广播规则。
%timeit np.where(df['B'] == 0, 0, df['A'] / df['B']) # 1.17 ms
%timeit (df['A'] / df['B']).replace([np.inf, -np.inf], 0) # 1.96 ms
当循环被认为是可行的时,它们通常通过numba
进行优化,并使用底层NumPy数组尽可能多地移动到C。
确实,numba
将性能提高到微秒级。如果没有一些繁琐的工作,就很难得到比这更有效率的多。
from numba import njit
@njit
def divide(a, b):
res = np.empty(a.shape)
for i in range(len(a)):
if b[i] != 0:
res[i] = a[i] / b[i]
else:
res[i] = 0
return res
%timeit divide(df['A'].values, df['B'].values) # 717 µs
使用@njit(parallel=true)
可以进一步促进更大的数组。
我有一个列表,我想创建一个名为的扩展。 我不想覆盖,因此不能使用append、extend或insert。我想知道是否有一个快速的方法来完成这项工作(比使用理解列表或Deep.copy更快)
问题内容: 我建立了一个分析引擎,可以从数据库中提取50-100行原始数据(称为),在PHP上对其进行一堆统计测量,然后精确给出140个数据点,然后将它们存储在另一个表中(让我们称之为)。所有这些数据点都是非常小的整数(“ 40”,“ 2.23”,“-1024”是数据类型的很好的示例)。 我知道mysql的最大列数非常高(4000+),但是当性能真正开始下降时,似乎有很多灰色区域。 这里有一些关于
问题内容: 有一个对象列表。 使用它创建一个unmodifiableList。 我了解不支持添加/删除/设置操作。同时,它不是不变的,因为它引用了现有的可修改列表,并且每当对该列表进行更改时,这些更改也会反映出来。 这样就创建了一个不可变的列表。 由于使用了转换构造函数,因此创建了一个不可变的列表。无法执行添加/删除/设置操作,原始列表中的任何更改都不会反映在中。让我们假设对象也是不可变的。 现在
我正在尝试查看我们是否可以使用 spark/scala 从 dataFrame 中某个列中的值创建新列。我有一个数据帧,其中包含以下数据 在上面的数据中,col1/col2/col3是列名,后跟它的值。列名和值由< code >,分隔。每组由< code>|分隔。 现在,我想做到这一点 感谢任何帮助。
我有一个很大的数据集,其中有许多带有状态的列。我想做一个新的专栏,有参与者的当前状态。我试图在dplyr中使用case_when,但我不确定如何跨列。数据集的列太多,我无法键入每一列。以下是数据示例: 对于代码,我想要一个新的列,列中说明参与者的最终状态;然而,如果他们的状态曾经是完成的,那么我希望它说完成,不管他们的最终状态是什么。对于该数据,答案如下所示: 还有,如果你能包括对你的代码的任何解
问题内容: 我有一个应用程序,该应用程序可以获取制造过程的质量结果,并创建图形以显示不良品的帕累托图,并显示生产量。 为了自动化测试这些统计程序的任务,我希望确定性地能够将记录添加到数据库中,并使质量技术能够进入某些图表并与已知的良好图表进行比较。但是,我也想模拟结果,以便将它们像进入用户整个测试过程一样进入数据库。 我有一个想法是用i好的数字,j的坏数字1,k的坏数字2等填充一个列表,然后以某种