我有一个非常大的DataFrame,其中每个元素都填充有1-5个整数,如果没有该元素的数据,则为0。我想为其创建两个调整后的副本:
train
将是一个副本,其中每行随机将20%的非零元素设置为0 test
将是一个副本,其中除了这些相同的20%元素外,所有其他元素均设置为0 以下是示例:
ORIGINAL
0 1 2 3 4 5 6 7 8 9
0 3 0 1 1 3 5 3 5 4 2
1 4 2 3 2 3 3 4 4 1 2
2 2 4 2 5 4 4 0 0 4 2
TRAIN
0 1 2 3 4 5 6 7 8 9
0 3 0 0 1 3 5 3 5 4 2
1 4 2 3 0 3 3 4 4 0 2
2 2 4 2 5 4 4 0 0 4 0
TEST
0 1 2 3 4 5 6 7 8 9
0 0 0 1 0 0 0 0 0 0 0
1 0 0 0 2 0 0 0 0 1 0
2 0 0 0 0 0 0 0 0 0 2
这是我当前的蛮力算法,可以完成工作,但是速度太慢:
train, test = original.copy(), original.copy()
for i in range(original.shape[0]):
print("{} / {}".format(i + 1, original.shape[0]))
row = original.iloc[i] # Select row
nonZeroIndices = np.where(row > 0)[0] # Find all non-zero indices
numTest = int(len(nonZeroIndices) * 0.2) # Calculate 20% of this amount
rand = np.random.choice(nonZeroIndices, numTest, replace=False) # Select a rancom 20% of non-zero indices
for j in range(original.shape[1]):
if j in rand:
train.iloc[i, j] = 0
else:
test.iloc[i, j] = 0
是否可以使用Pandas或Numpy来实现这一目标?
答案 0 :(得分:2)
一种方法是
def make_train_test(df):
train, test = df.copy(), df.copy()
for i, row in df.iterrows():
non_zero = np.where(row > 0)[0]
num_test = int(len(non_zero) * 0.2)
rand = np.random.choice(non_zero, num_test, replace=False)
row_train = train.iloc[i, :]
row_test = test.iloc[i, :]
row_train[rand] = 0
row_test[~row_test.index.isin(rand)] = 0
return train, test
在我的测试中,此过程运行约4.85毫秒,原始解决方案运行约9.07毫秒,andrew_reece(否则为优雅)的解决方案运行15.6毫秒。
答案 1 :(得分:1)
首先,使用sample()
创建非零值的20%子集:
subset = df.apply(lambda x: x[x.ne(0)].sample(frac=.2, random_state=42), axis=1)
subset
1 2 5 8
0 NaN 1.0 NaN 4.0
1 2.0 NaN NaN 1.0
2 4.0 NaN 4.0 NaN
现在可以通过将train
与原始test
乘以subset
和df
并将fill_value
使用1或0来设置{1}}
train = df.apply(lambda x: x.multiply(subset.iloc[x.name].isnull(), fill_value=1), axis=1)
train
0 1 2 3 4 5 6 7 8 9
0 3 0 0 1 3 5 3 5 0 2
1 4 0 3 2 3 3 4 4 0 2
2 2 0 2 5 4 0 0 0 4 2
test = df.apply(lambda x: x.multiply(subset.iloc[x.name].notnull(), fill_value=0), axis=1)
test
0 1 2 3 4 5 6 7 8 9
0 0 0 1 0 0 0 0 0 4 0
1 0 2 0 0 0 0 0 0 1 0
2 0 4 0 0 0 4 0 0 0 0
数据:
df
0 1 2 3 4 5 6 7 8 9
0 3 0 1 1 3 5 3 5 4 2
1 4 2 3 2 3 3 4 4 1 2
2 2 4 2 5 4 4 0 0 4 2