Создание пустого массива NumPy и постепенное его заполнение
На данный момент программа постепенно записывает в пустой список большой объём данных. Делает примерно так:
import time
# Создаю пустые списки
z_gyro_row = []
collect_time_row = []
START_TIME = time.time()
# В цикле по определённому условию считываю данные с датчика
# И постепенно заполняю пустые списки
while flag:
collect_time = time.time() - START_TIME # Фиксируем отрезок времени
collect_time_row.append(collect_time) # Запись времени в список
z_gyro_32 = gyro_out32(z_gyro_32) # Считываю значение с датчика
z_gyro_row.append(z_gyro_32) # Запись значений в список
На один из моих вопросов, мне посоветовали для большого объёма данных использовать массивы NumPy. Сейчас я это попытался сделать, но как я понимаю их невозможно так же как и списки постепенно заполнять данными с помощью команды .append. Попытался так, но не вышло:
import numpy as np
my_array = np.array([], 'float64')
np.append(my_array, 10)
Возможно только преобразовать list в numpy.ndarray. В связи с этим возникает вопрос как оптимально использовать массивы NumPy, чтобы тратить как можно меньше времени и ресурсов на запись/хранение/обработку данных?
Ответы (3 шт):
Массив не изменяем
import numpy as np
my_array = np.array(['a', 'd'])
my_array2 = np.append(my_array, 'w', )
print(my_array)
print(my_array2)
Использование np.append :
my_array = np.array([0])
for i in range(int(10)):
my_array = np.append(my_array , i)
Использование python преобразования списка в массив после этого:
my_list= [0]
for k in range(int(10)):
my_array.append(k)
my_array = np.array(my_array )
Предварительное выделение массива numpy:
e = np.zeros((n,))
for k in range(n):
e[k] = k
Да, массивы - неизменяемый (не расширяемый) тип данных. Это цена за скорость работы. Вообще-то ничего нового и страшного: классические массивы в том-же С++ именно так и работают. Уже десятки лет. И еще столько-же будут использоваться и работать.
Теперь что делать. Самое худшее из возможных решений - работать с ними как со списками, т.е. порождать пустым, а потом добавлять по мере необходимости по одному элементу. Разумный путь - определить максимально возможное (в будущем) количество элементов в массиве, порождать массив именно такого размера, а потом заполнять его элементы по мере их появления. Промежуточный путь - породить массив большого (достаточного на первое время функционирования) размера, после исчерпания - добавлять новый фрагмент (опять - не на один элемент, конечно).
Поскольку у вас работа идет - мне так кажется - с датчиками, то у вас еще меньше проблем должно возникнуть, если конечно архитектуру приложения разработать нормально. В таких приложениях - нет необходимости хранить информацию бесконечно долго. Более того, есть такое понятие - окно наблюдения. По сути, сколько данных вы обрабатываете. И это окно как правило коненчо. Вот и создавайте массив соответствующего размера. Или два таких массива - один заполняется, данные из второго - обрабатываются. Кстати - заполнять можно действительно через список, который по только факту полного заполнения преобразуется в массив. Потом массивы меняются местами - второй наполняется, первый обрабатывается. Но архитектуру конечно надо при этом делать не спонтанно-интуитивно.
Если данных не очень много (не миллионы значений), то вам вообще не имеет смысла мучиться с Numpy. Я потестил ради интереса, создал пустой список из добавил к нему по одному 1 000 000 (миллион) элементов. На это у питона ушло 100 миллисекунд.
Если такая скорость для вас мала, то тогда нужно выделять массив Numpy, например, с помощью np.empty заведомо большего размера, чем вам может понадобится, и заполнять его, обращаясь к элементам по индексу. Но это не так удобно, как работать со списком.
А ещё в питоне есть разные виды очередей, например, очень удобная collections.deque, которую можно читать и писать с обоих концов. Если вы то пишете в список, то читаете из него вперемешку, то использовать очередь ещё проще и удобнее, чем список. Опять же на примере миллиона элементов создание очереди путём добавления элементов с конца и с начала по очереди, а потом полное опустошение очереди опять же забиранием элементов с конца и с начала по очереди заняло чуть больше тех же 100 миллисекунд. Очень рекомендую очередь - весьма удобная коллекция.