Chcę powtórzyć elementy tablicy wzdłuż osi 0 i AXIS 1 dla M i N razy odpowiednio:

import numpy as np

a = np.arange(12).reshape(3, 4)
b = a.repeat(2, 0).repeat(2, 1)
print(b)

[[ 0  0  1  1  2  2  3  3]
 [ 0  0  1  1  2  2  3  3]
 [ 4  4  5  5  6  6  7  7]
 [ 4  4  5  5  6  6  7  7]
 [ 8  8  9  9 10 10 11 11]
 [ 8  8  9  9 10 10 11 11]]

To działa, ale chcę wiedzieć, że są lepsze metody bez tworzenia tymczasowej tablicy.

21
HYRY 5 październik 2011, 08:17

4 odpowiedzi

Najlepsza odpowiedź

Możesz użyć produktu Kronecker, patrz numpy.kron:

>>> a = np.arange(12).reshape(3,4)
>>> print np.kron(a, np.ones((2,2), dtype=a.dtype))
[[ 0  0  1  1  2  2  3  3]
 [ 0  0  1  1  2  2  3  3]
 [ 4  4  5  5  6  6  7  7]
 [ 4  4  5  5  6  6  7  7]
 [ 8  8  9  9 10 10 11 11]
 [ 8  8  9  9 10 10 11 11]]

Twoja oryginalna metoda jest również w porządku!

14
wim 18 styczeń 2017, 17:14

Możesz użyć np.broadcast_to tutaj:

def broadcast_tile(a, h, w):
    x, y = a.shape
    m, n = x * h, y * w
    return np.broadcast_to(
        a.reshape(x, 1, y, 1), (x, h, y, w)
    ).reshape(m, n)

broadcast_tile(a, 2, 2)
array([[ 0,  0,  1,  1,  2,  2,  3,  3],
       [ 0,  0,  1,  1,  2,  2,  3,  3],
       [ 4,  4,  5,  5,  6,  6,  7,  7],
       [ 4,  4,  5,  5,  6,  6,  7,  7],
       [ 8,  8,  9,  9, 10, 10, 11, 11],
       [ 8,  8,  9,  9, 10, 10, 11, 11]])

wydajność


funkcje

def chris(a, h, w):
    x, y = a.shape
    m, n = x * h, y * w
    return np.broadcast_to(
        a.reshape(x, 1, y, 1), (x, h, y, w)
    ).reshape(m, n)

def alex_riley(a, b0, b1):
    r, c = a.shape
    rs, cs = a.strides
    x = np.lib.stride_tricks.as_strided(a, (r, b0, c, b1), (rs, 0, cs, 0))
    return x.reshape(r*b0, c*b1)

def paul_panzer(a, b0, b1):
    r, c = a.shape
    out = np.empty((r, b0, c, b1), a.dtype)
    out[...] = a[:, None, :, None]
    return out.reshape(r*b0, c*b1)

def wim(a, h, w):
    return np.kron(a, np.ones((h,w), dtype=a.dtype))

Konfiguracja

import numpy as np
import pandas as pd
from timeit import timeit

res = pd.DataFrame(
       index=['chris', 'alex_riley', 'paul_panzer', 'wim'],
       columns=[5, 10, 20, 50, 100, 500, 1000],
       dtype=float
)

a = np.arange(100).reshape((10,10))

for f in res.index:
    for c in res.columns:
        h = w = c
        stmt = '{}(a, h, w)'.format(f)
        setp = 'from __main__ import h, w, a, {}'.format(f)
        res.at[f, c] = timeit(stmt, setp, number=50)

Wyjście

enter image description here

7
user3483203 15 wrzesień 2018, 21:36

Ponieważ wynik nie może być wdrażany jako widok, as_strided nie oferuje żadnych korzyści nad prostą wstępną wstępną i nadawaniem. Z powodu jego nad głowa as_strided wydaje się być nieco wolniejszy (jednak nie zrobiłem właściwego benchmarkingu).

Kod as_strided jest pobierany z @ Alexriley's Post.

from numpy.lib.stride_tricks import as_strided
import numpy as np

def tile_array(a, b0, b1):
    r, c = a.shape                                    # number of rows/columns
    rs, cs = a.strides                                # row/column strides 
    x = as_strided(a, (r, b0, c, b1), (rs, 0, cs, 0)) # view a as larger 4D array
    return x.reshape(r*b0, c*b1)                      # create new 2D array

def tile_array_pp(a, b0, b1):
    r, c = a.shape
    out = np.empty((r, b0, c, b1), a.dtype)
    out[...] = a[:, None, :, None]
    return out.reshape(r*b0, c*b1)

a = np.arange(9).reshape(3, 3)

kwds = {'globals': {'f_ar': tile_array, 'f_pp': tile_array_pp, 'a': a},
        'number': 1000}

from timeit import timeit

print('as_strided', timeit('f_ar(a, 100, 100)', **kwds))
print('broadcast ', timeit('f_pp(a, 100, 100)', **kwds))

Przykładowy przebieg:

as_strided 0.048387714981799945
broadcast  0.04324757700669579
4
Pedro Gaspar 26 listopad 2018, 19:21

Innym rozwiązaniem jest użycie as_strided. kron jest znacznie wolniejszy, a następnie dwukrotnie przy użyciu repeat. Znalazłem, że as_strided jest znacznie szybszy niż podwójny {x4}} w wielu przypadkach (małe tablice [250x250] tylko podwojenie w każdym wymiarze as_strided był wolniejszy). Sztuczka as_strided jest następująca:

a = arange(1000000).reshape((1000, 1000)) # dummy data

from numpy.lib.stride_tricks import as_strided
N, M = 4,3 # number of time to replicate each point in each dimension
H, W = a.shape
b = as_strided(a, (H, N, W, M), (a.strides[0], 0, a.strides[1], 0)).reshape((H*N, W*M))

Działa to przy użyciu 0-długich kroków, co powoduje, że Numpy przeczytanie tej samej wartości wielokrotnie (aż dojdzie do następnego wymiaru). Final reshape robi kopiowanie danych, ale tylko raz w przeciwieństwie do przy użyciu podwójnego repeat, który dwukrotnie skopiuje dane.

3
coderforlife 11 październik 2015, 02:56