Векторизованное задание в Numpy - PullRequest
0 голосов
/ 29 июня 2018

Давайте предположим, что у меня есть большой двумерный массив, например 1000x1000 элементов. У меня также есть два одномерных целочисленных массива длины L и плавающий одномерный массив одинаковой длины. Если я хочу просто присвоить числа с плавающей точкой различным позициям в исходном массиве в соответствии с целочисленным массивом, я мог бы написать:

mat = np.zeros((1000,1000))
int1 = np.random.randint(0,999,size=(50000,))
int2 = np.random.randint(0,999,size=(50000,))
f = np.random.rand(50000)
mat[int1,int2] = f

Но если бы произошли столкновения, то есть несколько поплавков, соответствующих одному местоположению, все, кроме последнего, были бы перезаписаны. Есть ли способ как-то агрегировать все коллизии, например, среднее значение или медиана всех поплавков, падающих в одном месте? Я хотел бы воспользоваться векторизацией и, надеюсь, избежать циклов интерпретатора.

Спасибо!

Ответы [ 3 ]

0 голосов
/ 29 июня 2018

Вы можете манипулировать своими данными в pandas и затем назначать.

Начиная с

mat = np.zeros((1000,1000))
a = np.random.randint(0,999,size=(50000,))
b = np.random.randint(0,999,size=(50000,))
c = np.random.rand(50000)

Вы можете определить функцию

def get_aggregated_collisions(a,b,c):
    df = pd.DataFrame({'x':a, 'y':b, 'v':c})
    df['coord'] = df[['x','y']].apply(tuple,1)
    d = df.groupby('coord').agg({"v":'mean','x':'first', 'y':'first'}).to_dict('list')
    return d

, а затем

d = get_aggregated_collisions(a,b,c)
mat[d['x'], d['y']] = d['v']

Вся операция (включая генерацию матриц, np.random и т. Д.) Прошла нормально

1.05 s ± 30.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Идея создания tuple координат заключалась в том, чтобы иметь хешируемую опцию для группировки значений по их координатам. Может быть, есть даже более разумный способ сделать это :) всегда открыт для предложений.

0 голосов
/ 29 июня 2018

Мой тест основан на ответе RafaelC.

Сначала выполните groupby для ["x", "y"], затем возьмите mean или median каждой группы и, наконец, сбросьте индекс с помощью reset_index().

import pandas as np
# setup
mat = np.zeros((1000,1000))
a = np.random.randint(0,999,size=(50000,))
b = np.random.randint(0,999,size=(50000,))
c = np.random.rand(50000)
# Start here
df = pd.DataFrame({"x":a, "y":b, "val":c})
v = df.groupby(["x", "y"]).mean().reset_index()
mat[v["x"], v["y"]] += v["val"]

Если нужны медианы, измените v на

v = df.groupby(["x", "y"]).median().reset_index()
0 голосов
/ 29 июня 2018

Основываясь на предложении hpaulj, вот как получить среднее значение в случае столкновений:

import numpy as np

mat = np.zeros((2,2))
int1 = np.zeros(2, dtype=int)
int2 = np.zeros(2, dtype=int)
f = np.array([0,1])

np.add.at(mat, [int1, int2], f)
n = np.zeros((2,2))
np.add.at(n, [int1, int2], 1)
mat[int1, int2] /= n[int1, int2]
print(mat)

array([[0.5, 0. ],
       [0. , 0. ]])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...