Нарезка шаблона в большом 1-м массиве NumPy - PullRequest
0 голосов
/ 20 декабря 2018

У меня есть 1-й массив, где у меня есть образец в энтери.Я приведу пример.В массиве arr у меня есть первые 4 записи с одной цифрой, следующие 4 записи с двумя цифрами, а затем следующие 6 записей с 3 цифрами.( Эта единичная, двузначная, тройная цифра предназначена только для выделения шаблона. Фактический массив имеет числа с плавающей запятой с одинаковыми значениями). Пример 1-го массива выглядит следующим образом:

import numpy as np
arr = np.array([1, 2, 3, 4, 11, 12, 13, 14, 111, 123, 132, 145, 176, 129, 
                6, 5, 3, 2, 21, 82, 53, 34, 121, 133, 139, 165, 186, 119])

Теперь у одного полного шаблона всего 4 + 4 + 6 = 14 единиц.Этот шаблон (или повторяющаяся единица) повторяется несколько сотен тысяч раз, поэтому длина моего массива кратна 14 (14 * 2 = 28 в примере arr выше).

Вопрос:

Я хочу извлечь все однозначные записи (первые 4 числа одной повторяющейся единицы), все двухзначные записи (следующие 4 числа одногоповторяющаяся единица) и все трехзначные записи (следующие 6 цифр одной повторяющейся единицы).

Таким образом, я хочу разделить мои большие arr на три 1-мерных массива.Таким образом, желаемый результат равен

arr1 = array([1, 2, 3, 4, 6, 5, 3, 2])
arr2 = array([11, 12, 13, 14, 21, 82, 53, 34])
arr3 = array([111, 123, 132, 145, 176, 129, 121, 133, 139, 165, 186, 119])

Моя идея

Одним из способов может быть просто reshape его в 2d массив, так как я знаюколичество повторений (= 28/14 = 2 в примере arr), а затем используйте индексацию, чтобы получить все первые куски 4, 4 и 6, а затем concatenate.

arr = arr.reshape(2, 14)

, а затем использовать нарезку, чтобы получить куски как

arr1 = np.concatenate(arr[:, 0:4])
arr2 = np.concatenate(arr[:, 4:8])
arr3 = np.concatenate(arr[:, 8:])
print (arr1, arr2, arr3)

# array([1, 2, 3, 4, 6, 5, 3, 2]),
# array([11, 12, 13, 14, 21, 82, 53, 34]),
# array([111, 123, 132, 145, 176, 129, 121, 133, 139, 165, 186, 119]))

Но мне интересно узнать альтернативное и эффективное решение, использующее какое-то маскирование и нарезка без преобразования сначала в 2-й массив.

Ответы [ 4 ]

0 голосов
/ 05 июня 2019

Мы могли бы просто изменить форму на 2D (помните, что изменение формы создает представление и имеет нулевые накладные расходы памяти и, следовательно, практически свободно во время выполнения) с числом столбцов, равным длине шаблона (14 в примере).Затем slice выводит первые 4 записи для первого вывода массива, следующие 4 для второго и 8-го столбцов для последнего.

Поскольку нам нужен плоский вывод, мы можем сделать это с помощью .ravel().

Следовательно -

In [44]: a2d = arr.reshape(-1,14) # 2d view into arr
    ...: arr1,arr2,arr3 = a2d[:,:4].ravel(),a2d[:,4:8].ravel(),a2d[:,8:].ravel()

In [45]: arr1
Out[45]: array([1, 2, 3, 4, 6, 5, 3, 2])

In [46]: arr2
Out[46]: array([11, 12, 13, 14, 21, 82, 53, 34])

In [47]: arr3
Out[47]: array([111, 123, 132, 145, 176, 129, 121, 133, 139, 165, 186, 119])

Теперь, скажем, у нас все в порядке с выходами двумерного массива, затем -

In [48]: arr1,arr2,arr3 = a2d[:,:4],a2d[:,4:8],a2d[:,8:]

In [49]: arr1
Out[49]: 
array([[1, 2, 3, 4],
       [6, 5, 3, 2]])

In [50]: arr2
Out[50]: 
array([[11, 12, 13, 14],
       [21, 82, 53, 34]])

In [51]: arr3
Out[51]: 
array([[111, 123, 132, 145, 176, 129],
       [121, 133, 139, 165, 186, 119]])

Итак, зачем это делать?Потому что это просмотр исходного ввода arr и, следовательно, как уже упоминалось ранее, он имеет нулевую нагрузку на память и практически свободен -

In [52]: np.shares_memory(arr,arr1)
Out[52]: True

и т. Д. Для двух других массивов.

0 голосов
/ 20 декабря 2018

Вы можете получить прямой доступ к индексам

import numpy as np
arr = np.array([1, 2, 3, 4, 11, 12, 13, 14, 111, 123, 132, 145, 176, 129,
                6, 5, 3, 2, 21, 82, 53, 34, 121, 133, 139, 165, 186, 119])

run_length = 14
repetitions = 2

indices1 = [run_length * i + j for i in range(repetitions) for j in range(4)]
arr1 = arr[indices1]

indices2 = [run_length * i + j for i in range(repetitions) for j in range(4, 8)]
arr2 = arr[indices2]

indices3 = [run_length * i + j for i in range(repetitions) for j in range(8, 14)]
arr3 = arr[indices3]

print(arr1)
print(arr2)
print(arr3)

Вывод

[1 2 3 4 6 5 3 2]
[11 12 13 14 21 82 53 34]
[111 123 132 145 176 129 121 133 139 165 186 119]

Вы можете поместить все в функцию, подобную этой:

import numpy as np
arr = np.array([1, 2, 3, 4, 11, 12, 13, 14, 111, 123, 132, 145, 176, 129,
                6, 5, 3, 2, 21, 82, 53, 34, 121, 133, 139, 165, 186, 119])


def extract(arr, run_length, repetitions, pattern_lengths):
    chunks = [0] + np.cumsum(pattern_lengths).tolist()

    for start, end in zip(chunks, chunks[1:]):
        indices = [run_length * i + j for i in range(repetitions) for j in range(start, end)]
        yield arr[indices]


arr1, arr2, arr3 = list(extract(arr, 14, 2, [4, 4, 6]))

print(arr1)
print(arr2)
print(arr3)
0 голосов
/ 20 декабря 2018

Вы также можете построить маску:

# if you know where your indices are, otherwise use a formula
mask = np.zeros((3, 2, 14), dtype=bool)
mask[0,:, 0:4] = True
mask[1,:, 4:8] = True
mask[2,:, 8:] = True

arr1, arr2, arr3 = (arr[m.flatten()] for m in mask)
print (arr1, arr2, arr3)
0 голосов
/ 20 декабря 2018

Используя маску шаблона в соответствии с запросом (и предполагая, что длина arr является точным кратным длине маски):

mask1 = [True]*4 + [False]*10
mask2 = [False]*4 + [True]*4 + [False]*6
mask3 = [False]*8 + [True]*6

Затем вы напрямую получаете нужные массивы, выполняя:

n_masks = (len(arr) // len(mask1))
arr1 = arr[mask1 * n_masks]
arr2 = arr[mask2 * n_masks]
arr3 = arr[mask3 * n_masks]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...