Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 更快、更友好地完成此算法?_Python_Pandas_Numpy - Fatal编程技术网

Python 更快、更友好地完成此算法?

Python 更快、更友好地完成此算法?,python,pandas,numpy,Python,Pandas,Numpy,我有一个非常大的数据框,其中每个元素都填充了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

我有一个非常大的数据框,其中每个元素都填充了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有没有更快的方法来实现这一点?

一种方法是

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毫秒。

首先,使用
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
现在可以通过将
子集
与原始
df
相乘,并使用1s或0s作为
填充值来设置
列车
测试

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.sample
中的
random_state
是否只是为了再现性?我真的不需要它吗?不客气。这是正确的,在这里设置
random_state
只是为了再现性,您不需要它。这实际上似乎比给定测试数据集上的原始解决方案慢得多(参见下面答案中的计时)。与我在大数据帧上的解决方案相比,它实际上快得惊人(秒vs分钟)的确,熊猫的奔跑速度通常比它所覆盖的一些Numpy方法要慢。而使用
apply
基本上是一个美化的for循环,没有巨大的矢量化收益。我想可能有一种很好的方法可以一次绘制整个
子集
,而不是像这里的
apply()
那样对每一行调用
sample()
。欢迎编辑!我理解你的方法可能更快,但我的目标是提高我与熊猫的技能,而这个问题特别要求更友好的解决方案,因此我保留安德鲁·里斯的答案作为公认的答案。不过,还是投票支持效率。很好的效率@fuglede!
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