Помещает ли numy массив в список pythonic? - PullRequest
0 голосов
/ 06 июля 2018

Я пытаюсь разбить длинную последовательность на подпоследовательность с меньшим размером окна, используя функцию get_slice, определенную мной. Затем я внезапно осознал, что мой код слишком неуклюжий, поскольку мои необработанные данные уже являются массивом numpy, и мне нужно сохранить их в списке в моей функции get_slice. После этого, когда я читаю каждую строку в data_matrix, мне нужен еще один список для повторного сохранения информации.

Код работает нормально, но преобразование между массивом numpy и списком туда-сюда кажется мне непитонным. Интересно, правильно ли я это делаю. Если нет, то как сделать это более эффективно и более питонно?

Вот мой код:

import numpy as np

##Artifical Data Generation##
X_row1 = np.linspace(1,60,60,dtype=int) 
X_row2 = np.linspace(101,160,60,dtype=int)
X_row3 = np.linspace(1001,1060,60,dtype=int) 

data_matrix = np.append(X_row1.reshape(1,-1),X_row2.reshape(1,-1),axis=0)
data_matrix = np.append(data_matrix,X_row3.reshape(1,-1,),axis=0)
##---------End--------------##

##The function for generating time slice for sequence##
def get_slice(X,windows=5, stride=1):
    x_slice = []
    for i in range(int(len(X)/stride)):
        if i*stride < len(X)-windows+1:
            x_slice.append(X[i*stride:i*stride+windows])

    return np.array(x_slice)
##---------End--------------##

x_list = []
for row in data_matrix:
    temp_data = get_slice(row) #getting time slice as numpy array
    x_list.append(temp_data) #appending the time slice into a list

X = np.array(x_list) #Converting the list back to numpy array

Ответы [ 3 ]

0 голосов
/ 06 июля 2018

В очень редких случаях требуется смешивание списка и массива. Вы можете эффективно иметь те же данные только с массивными примитивами:

data_matrix=np.add.outer([0,100,1000],np.linspace(1,60,60,dtype=int))
X=np.lib.stride_tricks.as_strided(data_matrix2,shape=(3, 56, 5),strides=(4*60,4,4))

Это просто вид. Свежий массив можно получить по X=X.copy().

0 голосов
/ 10 июля 2018

Помещая это здесь как полу-полный ответ для решения ваших двух вопросов - делая код более "питоническим" и более "эффективным".

Существует множество способов написания кода, и всегда можно найти баланс между количеством кода, который используется просто, и чистого кода Python. Большая часть этого сводится к опыту с NumPy и знанию некоторых более продвинутых функций, скорости выполнения кода и личных предпочтений. Личные предпочтения являются наиболее важными - вам нужно уметь понимать, что делает ваш код, и изменять его. Не беспокойтесь о том, что является питоническим или, что еще хуже, нумфитоническим. Найдите стиль кодирования, который работает для вас (как вы, кажется, сделали), и не прекращайте учиться. Вы поймете некоторые уловки (например, использует ответ @ B.M.), но по большей части они должны быть сохранены для редких случаев. Большинство трюков, как правило, требуют дополнительной работы или применяются только при некоторых обстоятельствах.

Это поднимает вторую часть вашего вопроса. Как сделать код более эффективным. Первый шаг - это сравнить его. В самом деле. Я был удивлен количеством вещей, которые, как я думал, ускорили код, который едва изменил его или даже заставил работать медленнее. Списки Python сильно оптимизированы и обеспечивают хорошую производительность для многих вещей (хотя многие пользователи здесь, в stackoverflow, убеждены, что использование numpy может волшебным образом ускорить любой код).

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

  1. Вы заранее не знаете размер ваших данных (списки расширяются гораздо эффективнее)
  2. Вы создаете большое количество представлений в массиве (в этом случае список массивов часто дешевле, чем один большой массив)
  3. У вас есть данные неправильной формы (массивы должны быть квадратными)

В вашем коде применяется случай 2. Трюк с as_strided также сработает и, возможно, будет быстрее в некоторых случаях, но пока вы не профилируете и не узнаете, что это за дела, я бы сказал, что ваш код достаточно хорош.

0 голосов
/ 06 июля 2018

Добавление в список будет медленным. Попробуйте составить список, чтобы создать массив numpy.

что-то вроде ниже

import numpy as np

##Artifical Data Generation##
X_row1 = np.linspace(1,60,60,dtype=int)
X_row2 = np.linspace(101,160,60,dtype=int)
X_row3 = np.linspace(1001,1060,60,dtype=int)

data_matrix = np.append(X_row1.reshape(1,-1),X_row2.reshape(1,-1),axis=0)
data_matrix = np.append(data_matrix,X_row3.reshape(1,-1,),axis=0)
##---------End--------------##

##The function for generating time slice for sequence##
def get_slice(X,windows=5, stride=1):
    return np.array([X[i*stride:i*stride+windows]
                     for i in range(int(len(X)/stride))
                      if i*stride < len(X)-windows+1])
##---------End--------------##

X = np.array([get_slice(row) for row in data_matrix])
print(X)

Это может быть странно, потому что у вас есть множество пустых массивов. Если вам нужен трехмерный массив, это прекрасно. Если вам не нужен 3-мерный массив, то вы можете добавить vstack или добавить массивы.

# X = np.array([get_slice(row) for row in data_matrix])
X = np.vstack((get_slice(row) for row in data_matrix))

Скорость понимания списка

Я использую Python 3.4.4 в Windows 10.

import timeit


TEST_RUNS = 1000
LIST_SIZE = 2000000


def make_list():
    li = []
    for i in range(LIST_SIZE):
        li.append(i)
    return li


def make_list_microopt():
    li = []
    append = li.append
    for i in range(LIST_SIZE):
        append(i)
    return li


def make_list_comp():
    li = [i for i in range(LIST_SIZE)]
    return li


print("List Append:", timeit.timeit(make_list, number=TEST_RUNS))
print("List Comprehension:", timeit.timeit(make_list_comp, number=TEST_RUNS))
print("List Append Micro-optimization:", timeit.timeit(make_list_microopt, number=TEST_RUNS))

выход

List Append: 222.00971377954895
List Comprehension: 125.9705268094408
List Append Micro-optimization: 157.25782340883387

Я очень удивлен, насколько полезна микрооптимизация. Тем не менее, понимание списков намного быстрее для больших списков в моей системе.

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