манипулирование двумерной матрицей с использованием numpy логического индексирования занимает много времени - PullRequest
1 голос
/ 26 марта 2020

Я сгенерировал огромное количество случайных данных, например:

ndata = np.random.binomial(1, 0.25, (100000, 1000))

, то есть матрица 100 000 на 1000 (!)

Я генерирую новую матрицу, где для каждого строка, каждый столбец является истинным, если среднее значение всех столбцов заранее (за вычетом ожидаемой величины Бернулли Р.В. с р = 0,25) больше, чем равно некоторому эпсилону.

примерно так:

def true_false_inequality(data, eps, data_len):
    return [abs(np.mean(data[:index + 1]) - 0.25) >= eps for index in range(data_len)]

После этого я создаю 1-й массив (наконец-то!), Где каждый столбец представляет, сколько истинных значений у меня было в одном столбце в матрице, а затем я делю каждый столбец на некоторое число (exp_numer = 100,000 )

def final_res(data, eps):
    tf = np.array([true_false_inequality(data[seq], eps, data_len) for seq in range(exp_number)])
    percentage = tf.sum(axis=0)/exp_number
    return percentage

Также у меня есть 5 разных эпсилонов, которые я повторяю, чтобы получить мой окончательный результат 5 раз. (epsilons = [0,001, 0,1, 0,5, 0,25, 0,025])

Мой код работает , но это занимает много времени для 100 000 строк на 1000 столбцов, я знаю, что могу сделать это быстрее благодаря использованию функции numpy немного больше, но я просто не знаю как.

Ответы [ 2 ]

1 голос
/ 26 марта 2020

Вы можете выполнить весь расчет с векторизованными операциями над полным массивом данных:

mean = np.cumsum(data, axis=1) / np.arange(1, data.shape[1]+1)
condition = np.abs(mean - 0.25) >= eps
percentage = condition.sum(axis=0) / len(data)
0 голосов
/ 26 марта 2020

Вы можете рассчитать совокупное среднее с помощью:

np.cumsum(ndata, axis=0).sum(axis=1) / np.arange(1, 100001)

, чтобы мы могли оптимизировать true_false_inequality до:

def true_false_inequality(data, eps, data_len):
    cummean = np.cumsum(ndata, axis=0).sum(axis=1) / np.arange(1, data_len)
    return abs(cummean - 0.25) >= eps

Или как @a_guest предлагает мы можем сначала суммировать элементы, а затем вычислить совокупную сумму:

def true_false_inequality(data, eps, data_len):
    cummean = ndata.sum(axis=1).cumsum(axis=0) / np.arange(1, 100001)
    return abs(cummean - 0.25) >= eps
...