самый быстрый способ перебрать массив numpy и обновить каждый элемент - PullRequest
0 голосов
/ 27 мая 2018

Это может быть странно для вас, люди, но у меня есть эта странная цель, код выглядит следующим образом.

# A is a numpy array, dtype=int32,
# and each element is actually an ID(int), the ID range might be wide,
# but the actually existing values are quite fewer than the dense range,
A = array([[379621, 552965, 192509],
       [509849, 252786, 710979],
       [379621, 718598, 591201],
       [509849,  35700, 951719]])

# and I need to map these sparse ID to dense ones,
# my idea is to have a dict, mapping actual_sparse_ID -> dense_ID
M = {}

# so I iterate this numpy array, and check if this sparse ID has a dense one or not
for i in np.nditer(A, op_flags=['readwrite']):
    if i not in M:
        M[i] = len(M)  # sparse ID got a dense one
    i[...] = M[i]   # replace sparse one with the dense ID

Моя цель может быть достигнута с помощью np.unique(A, return_inverse=True) и return_inverse результат - это то, что я хочу.

Тем не менее, у меня есть массив, который у меня слишком велик для полной загрузки в память, поэтому я не могу запустить np.unique для всех данных, и именно поэтому я пришел к такому выводуидея картографирования ...

Это правильный путь?Любое возможное улучшение?

1 Ответ

0 голосов
/ 27 мая 2018

Я попытаюсь предоставить альтернативный способ сделать это, используя numpy.unique() для подмассивов.Это решение не полностью протестировано.Я также не проводил параллельной оценки производительности, поскольку ваше решение не работает для меня полностью.

Допустим, у нас есть массив c, который мы разбили на два меньших массива.Давайте создадим некоторые тестовые данные, например:

>>> a = np.array([[1,1,2,3,4],[1,2,6,6,2],[8,0,1,1,4]])
>>> b = np.array([[11,2,-1,12,6],[12,2,6,11,2],[7,0,3,1,3]])
>>> c = np.vstack([a, b])
>>> print(c)
[[ 1  1  2  3  4]
 [ 1  2  6  6  2]
 [ 8  0  1  1  4]
 [11  2 -1 12  6]
 [12  2  6 11  2]
 [ 7  0  3  1  3]]

Здесь мы предполагаем, что c - это большой массив, а a и b - это под-массивы.Конечно, сначала можно создать c, а затем extract под-массивов.

Следующий шаг - запустить numpy.unique() на двух под-массивах:

>>> ua, ia = np.unique(a, return_inverse=True)
>>> ub, ib = np.unique(b, return_inverse=True)
>>> uc, ic = np.unique(c, return_inverse=True) # this is for future reference

Теперь приведем алгоритм объединения результатов из подмассивов:

def merge_unique(ua, ia, ub, ib):
    # make copies *if* changing inputs is undesirable:
    ua = ua.copy()
    ia = ia.copy()
    ub = ub.copy()
    ib = ib.copy()

    # find differences between unique values in the two arrays:
    diffab = np.setdiff1d(ua, ub, assume_unique=True)
    diffba = np.setdiff1d(ub, ua, assume_unique=True)

    # find indices in ua, ub where to insert "other" unique values:
    ssa = np.searchsorted(ua, diffba)
    ssb = np.searchsorted(ub, diffab)

    # throw away values that are too large:
    ssa = ssa[np.where(ssa < len(ua))]
    ssb = ssb[np.where(ssb < len(ub))]

    # increment indices past previously computed "insert" positions:
    for v in ssa[::-1]:
        ia[ia >= v] += 1
    for v in ssb[::-1]:
        ib[ib >= v] += 1

    # combine results:
    uc = np.union1d(ua, ub) # or use ssa, ssb, diffba, diffab to update ua, ub
    ic = np.concatenate([ia, ib])
    return uc, ic

Теперь давайте запустим эту функцию для результатов numpy.unique() из подмассивов, а затем сравним объединенные индексы и уникальные значения.с эталонными результатами uc и ic:

>>> uc2, ic2 = merge_unique(ua, ia, ub, ib)
>>> np.all(uc2 == uc)
True
>>> np.all(ic2 == ic)
True

Разделение более чем на два подмассива может быть выполнено с небольшой дополнительной работой - просто продолжайте накапливать «уникальные» значения и индексы, например:

uacc, iacc = np.unique(subarr1, return_inverse=True)
ui, ii = np.unique(subarr2, return_inverse=True)
uacc, iacc = merge_unique(uacc, iacc, ui, ii)
ui, ii = np.unique(subarr3, return_inverse=True)
uacc, iacc = merge_unique(uacc, iacc, ui, ii)
ui, ii = np.unique(subarr4, return_inverse=True)
uacc, iacc = merge_unique(uacc, iacc, ui, ii)
................................ (etc.)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...