Numpy: транслировать значения строк в каналы - PullRequest
0 голосов
/ 01 декабря 2018

У меня есть набор данных, где первые 48 наблюдений - это временные ряды, а остальные 12 - статические переменные:

h1 h2 h3 h4 ... h48 v1 v2 v3 v4 v5 v6 .. vn
h1 h2 h3 h4 ... h48 v1 v2 v3 v4 v5 v6 .. vn

форма одного элемента (367, 60).

Я хочупередать переменные v1 v2 v3 v4 v5 v6 .. vn в качестве дополнительных каналов во временные ряды, т.е. создать массив формы (367, 48, 13).Я хочу сделать это на лету, так как полностью преобразованный набор данных не помещается в мою оперативную память.

Код, который я сейчас использую, очень неэффективен (items является пакетным):

def preprocessor(items):

    items_new = np.zeros(shape=(items.shape[0], 367, 48, 13), dtype=np.float32)

    for idx_item, item in enumerate(items):

        train_data = item[:,:48]
        train_vars = item[:,48:]

        train_new = np.zeros((train_data.shape[0], train_data.shape[1],(train_vars.shape[1]+1)))
        for idx_row, row in enumerate(train_data):
            for idx_col, elem in enumerate(row):
                train_new[idx_row, idx_col, :] = np.concatenate([[elem], train_vars[idx_row]])

        items_new[idx_item] = train_new

    return items_new

Можно ли сделать это быстрее без циклов?

РЕДАКТИРОВАТЬ:

Минимальный воспроизводимый пример:

arr = np.random.randn(5,367,60)

arr2 = preprocessor(arr)

print(arr2.shape) # (5, 367, 48, 13)

Ответы [ 2 ]

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

Это еще одно решение с использованием повторения и объединения.

a = items[:,:,:48, np.newaxis]
b = items[:,:,48:].repeat(a.shape[2], axis=1).reshape(*a.shape[:-1], -1)
return np.concatenate([a,b], axis=3)
0 голосов
/ 01 декабря 2018

Подход № 1

Мы могли бы использовать широковещательное присвоение массива для векторизованного решения -

def array_assign(items):    
    L = 48 # slice at this column ID
    N = items.shape[-1]
    out = np.empty(shape= items.shape[:2] + (L,N-L+1), dtype=np.float32)
    out[...,1:] = items[...,None,L:]
    out[...,0] = items[...,:L]
    return out

Подход № 2

Мы могли бы также использовать широковещательный просмотр и затем объединить -

def broadcast_concat(items):    
    L = 48 # slice at this column ID
    N = items.shape[-1]
    a = items[...,:L,None]
    shp_b = items.shape[:2] + (L,N-L)
    b = np.broadcast_to(items[...,None,L:],shp_b)
    out = np.concatenate((a,b),axis=-1)
    return out

Время -

In [321]: items = np.random.rand(5,367,60)

In [322]: %timeit array_assign(items)
1000 loops, best of 3: 923 µs per loop

In [323]: %timeit broadcast_concat(items)
1000 loops, best of 3: 781 µs per loop

Для честного сравнения, мы должны были бы позволить второму методу использовать более эффективныйfloat32 dtype также.Давайте используем этот dtype для настройки входных данных и снова протестируем -

In [335]: items = np.random.rand(5,367,60).astype(np.float32)

In [336]: %timeit array_assign(items)
1000 loops, best of 3: 897 µs per loop

In [337]: %timeit broadcast_concat(items)
1000 loops, best of 3: 348 µs per loop

Итак, для наиболее производительного случая для случая, когда требуется преобразование dtype, мы могли бы использовать items = np.asarray(items, dtype=np.float32) в начале подхода# 2.

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