python - 有没有更快的方法将熊猫数据框分成两个互补的部分?
问题描述
大家晚上好
我有一种情况,我需要根据一个特征的值将数据框分成两个互补的部分。
我的意思是,对于数据帧 1 中的每一行,我需要数据帧 2 中的互补行,该行具有该特定特征的相反值。
在我的源数据框中,我所指的功能存储在“773”列下,它可以采用0.0或1.0的值。
我想出了以下代码,可以充分做到这一点,但速度非常慢。拆分 10,000 行大约需要一分钟,即使在我功能强大的 EC2 实例上也是如此。
data = chunk.iloc[:,1:776]
listy1 = []
listy2 = []
for i in range(0,len(data)):
random_row = data.sample(n=1).iloc[0]
listy1.append(random_row.tolist())
if random_row["773"] == 0.0:
x = data[data["773"] == 1.0].sample(n=1).iloc[0]
listy2.append(x.tolist())
else:
x = data[data["773"] == 0.0].sample(n=1).iloc[0]
listy2.append(x.tolist())
df1 = pd.DataFrame(listy1)
df2 = pd.DataFrame(listy2)
注意:我不关心重复行,因为这些数据被用于训练一个模型,该模型比较两个对象以判断哪个对象“更好”。
您是否对为什么这么慢有一些见解,或者有什么建议可以加快速度?
解决方案
numpy
//高效编码的一个关键概念是尽可能使用库提供的矢量化函数scipy
。pandas
尝试一次处理多行,而不是显式地遍历行。即避免for
循环和.iterrows()
.
提供的实现在索引方面有点微妙,但向量化的思路应该直截了当,如下所示:
- 一次绘制主数据集。
- 互补数据集:一次绘制0行,一次绘制互补1行,然后一次将它们放入相应的行中。
代码:
import pandas as pd
import numpy as np
from datetime import datetime
np.random.seed(52) # reproducibility
n = 10000
df = pd.DataFrame(
data={
"773": [0,1]*int(n/2),
"dummy1": list(range(n)),
"dummy2": list(range(0, 10*n, 10))
}
)
t0 = datetime.now()
print("Program begins...")
# 1. draw the main dataset
draw_idx = np.random.choice(n, n) # repeatable draw
df_main = df.iloc[draw_idx, :].reset_index(drop=True)
# 2. draw the complementary dataset
# (1) count number of 1's and 0's
n_1 = np.count_nonzero(df["773"][draw_idx].values)
n_0 = n - n_1
# (2) split data for drawing
df_0 = df[df["773"] == 0].reset_index(drop=True)
df_1 = df[df["773"] == 1].reset_index(drop=True)
# (3) draw n_1 indexes in df_0 and n_0 indexes in df_1
idx_0 = np.random.choice(len(df_0), n_1)
idx_1 = np.random.choice(len(df_1), n_0)
# (4) broadcast the drawn rows into the complementary dataset
df_comp = df_main.copy()
mask_0 = (df_main["773"] == 0).values
df_comp.iloc[mask_0 ,:] = df_1.iloc[idx_1, :].values # df_1 into mask_0
df_comp.iloc[~mask_0 ,:] = df_0.iloc[idx_0, :].values # df_0 into ~mask_0
print(f"Program ends in {(datetime.now() - t0).total_seconds():.3f}s...")
查看
print(df_main.head(5))
773 dummy1 dummy2
0 0 28 280
1 1 11 110
2 1 13 130
3 1 23 230
4 0 86 860
print(df_comp.head(5))
773 dummy1 dummy2
0 1 19 190
1 0 74 740
2 0 28 280 <- this row is complementary to df_main
3 0 60 600
4 1 37 370
效率增益:14.23s -> 0.011s (ca. 128x)
推荐阅读
- java - 如何缩放画布以使我的应用程序占据整个屏幕?
- view - 如何在 nattable 和 Jface 视图之间交叉更新视图
- xcode - xcode pod swift 和 obj-c
- postgresql - Docker-compose Postgres 增加最大连接数
- reactjs - React-Redux 6 错误:在 props 中传递 redux 存储已被删除并且不执行任何操作
- github - 用 github 处理文件中的明文密码
- python - Bazel 在 TensorFlow 安装期间找不到 MSVC 2015
- antd - 将 AntD Form Button 置于与 Inputs 相同的级别
- raku - 角色访问可以包含角色属性吗?
- python - 错误 - unindent 不匹配任何外部缩进级别