我有两个数据帧s
和sk
,其中包含大约1M
个元素,我需要从其中生成一个新的数据帧df
,其中:
df.iloc[i] = s.iloc[f(i)] / sk.iloc[g(i)]
其中f
和g
是返回整数的函数。
目前我正在做
data = []
for i in range(s.shape[0])):
data.append(s.iloc[f(i)] / sk.iloc[g(i)])
df = pd.DataFrame(data, columns=s.columns)
但这似乎很慢。这大约需要5分钟(数据帧有9个float
列)。
只有10M
个部门,因此5分钟似乎不及标准。似乎所有时间都花在迭代s
和sk
上,所以我想知道是否有一种快速构建s[f]
和sk[g]
的方法?
修改
f
和g
是类似于
def f(i): return math.ceil(i / 23)
def g(i): return math.ceil(i / 23) + ((i - 1) % 23)
答案 0 :(得分:4)
您的函数很容易矢量化。
def f_vec(i):
return np.ceil(i / 23).astype(int)
def g_vec(i):
return (np.ceil(i / 23) + ((i - 1) % 23)).astype(int)
正如@Wen所指出的,我们可以通过编写一个包装器来只计算一次上限,从而进一步优化这一点。
def wrapper(i, a, b):
cache_ceil = np.ceil(i / 23).astype(int)
fidx = cache_ceil
gidx = cache_ceil + ((i - 1) % 23)
return a.iloc[fidx].to_numpy() / b.iloc[gidx].to_numpy()
这里的索引对齐也不适合您。如果您确实想要两个结果的按元素划分,请在划分之前先降到numpy
:
s.iloc[f_vec(idx)].to_numpy() / sk.iloc[g_vec(idx)].to_numpy()
现在可以测试速度了。
设置
a = np.random.randint(1, 10, (1_000_000, 10))
s = pd.DataFrame(a)
sk = pd.DataFrame(a)
idx = np.arange(1_000_000)
性能
%timeit s.iloc[f_vec(idx)].to_numpy() / sk.iloc[g_vec(idx)].to_numpy()
265 ms ± 5.28 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit wrapper(idx, s, sk)
200 ms ± 3.84 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)