Satır veya sütun vektörlerini “klonlama”


155

Bazen bir satır veya sütun vektörünü bir matrise "klonlamak" yararlı olabilir. Klonlama ile kastedilen bir satır vektörünü

[1,2,3]

Bir matrise

[[1,2,3]
 [1,2,3]
 [1,2,3]
]

veya bir sütun vektörü

[1
 2
 3
]

içine

[[1,1,1]
 [2,2,2]
 [3,3,3]
]

Matlab veya oktavda bu oldukça kolay bir şekilde yapılır:

 x = [1,2,3]
 a = ones(3,1) * x
 a =

    1   2   3
    1   2   3
    1   2   3

 b = (x') * ones(1,3)
 b =

    1   1   1
    2   2   2
    3   3   3

Bunu numpy olarak tekrarlamak istiyorum, ama başarısız

In [14]: x = array([1,2,3])
In [14]: ones((3,1)) * x
Out[14]:
array([[ 1.,  2.,  3.],
       [ 1.,  2.,  3.],
       [ 1.,  2.,  3.]])
# so far so good
In [16]: x.transpose() * ones((1,3))
Out[16]: array([[ 1.,  2.,  3.]])
# DAMN
# I end up with 
In [17]: (ones((3,1)) * x).transpose()
Out[17]:
array([[ 1.,  1.,  1.],
       [ 2.,  2.,  2.],
       [ 3.,  3.,  3.]])

İlk yöntem ( In [16]) neden çalışmadı? Bu görevi python'da daha zarif bir şekilde başarmanın bir yolu var mı?


6
Matlab'da, kullanmanın çok daha hızlı olduğuna dikkat edin repmat: repmat([1 2 3],3,1)veyarepmat([1 2 3].',1,3)
Luis Mendo

Oktav da var repmat.
31.11.2014

Bir panda veri çerçevesi ödeme ile benzer yapmak isteyenler için tile_df burada bağlantı
zelusp

Yanıtlar:


80

İşte bunu yapmanın zarif, Pythonic bir yolu:

>>> array([[1,2,3],]*3)
array([[1, 2, 3],
       [1, 2, 3],
       [1, 2, 3]])

>>> array([[1,2,3],]*3).transpose()
array([[1, 1, 1],
       [2, 2, 2],
       [3, 3, 3]])

ile ilgili sorun [16], devrik bir dizi için hiçbir etkisi yoktur gibi görünüyor. muhtemelen bunun yerine bir matris istiyorsunuz:

>>> x = array([1,2,3])
>>> x
array([1, 2, 3])
>>> x.transpose()
array([1, 2, 3])
>>> matrix([1,2,3])
matrix([[1, 2, 3]])
>>> matrix([1,2,3]).transpose()
matrix([[1],
        [2],
        [3]])

1
(transpoze etmek 2D diziler için çalışır, örneğin örnekteki kare için veya (N,1)kullanarak bir -shape dizisine dönüşürken .reshape(-1, 1))
Mark

34
Bu oldukça verimsizdir. PV.'nin cevabındanumpy.tile gösterildiği gibi kullanın .
David Heffernan

304

Kullanım numpy.tile:

>>> tile(array([1,2,3]), (3, 1))
array([[1, 2, 3],
       [1, 2, 3],
       [1, 2, 3]])

veya sütunları tekrarlamak için:

>>> tile(array([[1,2,3]]).transpose(), (1, 3))
array([[1, 1, 1],
       [2, 2, 2],
       [3, 3, 3]])

16
Oyla! Sistemimde, 1000 kez 1000 kez tekrarlanan bir vektör için tile, yöntem şu anda kabul edilen cevaptaki yöntemden (çarpma operatörü yöntemini kullanarak) 19.5 kat daha hızlıdır.
Dr.Jan-Philip Gehrcke

1
İkinci bölümde ("yinelenen sütunlar"), ikinci köşeli ayraç kümesinin ne yaptığını açıklayabilir misiniz, yani [[1,2,3]]
Ant

@İlk eksende 1 uzunluğu (ekranınızda dikey) ve ikinci eksende 3 uzunluğu (ekranınızda yatay) olan bir 2D diziye dönüşmez. Aktarma daha sonra birinci eksende 3 uzunluğuna ve ikinci eksende 1 uzunluğuna sahip olmasını sağlar. Döşeme şekli (1, 3)bu sütunu üç kez kopyalar, bu nedenle sonuç satırlarının her biri tek bir ayrı öğe içerir.
BallpointBen

Önceden başlatılmış herhangi bir vektörü geçebildiğiniz için bu kabul edilen cevap olmalıdır, ancak kabul edilen vektör yalnızca vektörü başlatırken virgül eklerseniz çalışabilir. Teşekkürler !
Yohan Obadia

Bunu 2d - 3d çözümü için
çalışamıyorum

42

İlk olarak, numpy'nin yayın işlemleri ile satır ve sütunları çoğaltmanın gerekli olmadığını unutmayın . Açıklamalar için bu ve buna bakın .

Ancak bunu yapmak için, tekrar ve newaxis muhtemelen en iyi yoldur

In [12]: x = array([1,2,3])

In [13]: repeat(x[:,newaxis], 3, 1)
Out[13]: 
array([[1, 1, 1],
       [2, 2, 2],
       [3, 3, 3]])

In [14]: repeat(x[newaxis,:], 3, 0)
Out[14]: 
array([[1, 2, 3],
       [1, 2, 3],
       [1, 2, 3]])

Bu örnek bir satır vektörü içindir, ancak bunu bir sütun vektörüne uygulamak umarım açıktır. tekrarlama bu kadar iyi heceliyor gibi görünüyor, ancak bunu örnekte olduğu gibi çarpma yoluyla da yapabilirsiniz

In [15]: x = array([[1, 2, 3]])  # note the double brackets

In [16]: (ones((3,1))*x).transpose()
Out[16]: 
array([[ 1.,  1.,  1.],
       [ 2.,  2.,  2.],
       [ 3.,  3.,  3.]])

5
newaxis ek veriye ihtiyaç duymadan gerçekte kopyalamaz. Yani bunu çoğaltmak veya başka bir 3x3 dizisine eklemek için yapıyorsanız, tekrarlama gereksizdir. Fikri almak için numpy yayınları okuyun.
AFoglia

@AFoglia - İyi bir nokta. Bunu belirtmek için cevabımı güncelledim.
tom10

1
np.repeatVs kullanmanın faydaları nelerdir np.tile?
mrgloom

@mrgloom: Bu vaka için çoğunlukla yok. Küçük bir 1D dizisi için benzerler ve önemli bir fark / fayda / avantaj / vb. Şahsen, satır ve sütun klonlama arasındaki simetriyi daha sezgisel buluyorum ve kiremit için gereken devri sevmiyorum, ama bu sadece bir zevk meselesi. Mateen Ulhaq'ın cevabı da tekrarın daha hızlı olduğunu söylüyor, ancak tekrar C-işlevselliğine çok daha yakın olmasına rağmen, dikkate alınan kullanım durumuna bağlı olabilir, bu yüzden muhtemelen biraz daha hızlı kalacaktır. 2D'de farklı davranışları vardır, bu yüzden orada önemlidir.
tom10

12

İzin Vermek:

>>> n = 1000
>>> x = np.arange(n)
>>> reps = 10000

Sıfır maliyet tahsisleri

Bir görünüm ek bellek gerektirmez. Bu nedenle, bu bildirimler anlıkdır:

# New axis
x[np.newaxis, ...]

# Broadcast to specific shape
np.broadcast_to(x, (reps, n))

Zorunlu dağıtım

İçeriğin bellekte kalmasını istiyorsanız:

>>> %timeit np.array(np.broadcast_to(x, (reps, n)))
10.2 ms ± 62.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

>>> %timeit np.repeat(x[np.newaxis, :], reps, axis=0)
9.88 ms ± 52.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

>>> %timeit np.tile(x, (reps, 1))
9.97 ms ± 77.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Her üç yöntem de kabaca aynı hızdadır.

Hesaplama

>>> a = np.arange(reps * n).reshape(reps, n)
>>> x_tiled = np.tile(x, (reps, 1))

>>> %timeit np.broadcast_to(x, (reps, n)) * a
17.1 ms ± 284 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

>>> %timeit x[np.newaxis, :] * a
17.5 ms ± 300 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

>>> %timeit x_tiled * a
17.6 ms ± 240 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Her üç yöntem de kabaca aynı hızdadır.


Sonuç

Bir hesaplamadan önce çoğaltma yapmak istiyorsanız, "sıfır maliyet ayırma" yöntemlerinden birini kullanmayı düşünün. "Zorunlu tahsis" performans cezası çekmeyeceksiniz.


8

Bence yayını numpy ile kullanmak en iyisi ve daha hızlı

Aşağıdaki gibi bir karşılaştırma yaptım

import numpy as np
b = np.random.randn(1000)
In [105]: %timeit c = np.tile(b[:, newaxis], (1,100))
1000 loops, best of 3: 354 µs per loop

In [106]: %timeit c = np.repeat(b[:, newaxis], 100, axis=1)
1000 loops, best of 3: 347 µs per loop

In [107]: %timeit c = np.array([b,]*100).transpose()
100 loops, best of 3: 5.56 ms per loop

yayını kullanarak yaklaşık 15 kat daha hızlı


NoneAynı şeyi yapmak için dizinleme yapabilirsiniz.
DanielSank

Newaxis nedir ?!
dreab

np.newaxis None
john ktejik

tekrar daha hızlıydı: 5.56 ms = 5560 µs
Augusto Fadel

4

Temiz bir çözüm NumPy'nin dış ürün işlevini bir vektörle kullanmaktır:

np.outer(np.ones(n), x)

nyinelenen satırlar verir . Yinelenen sütunları almak için bağımsız değişken sırasını değiştirin. Eşit sayıda satır ve sütun almak için

np.outer(np.ones_like(x), x)

3

Kullanabilirsiniz

np.tile(x,3).reshape((4,3))

karo vektörün tekrarlarını üretecektir

ve yeniden şekillendirme istediğiniz şekli verecektir


1

Bir panda veri çerçeveniz varsa ve kategorileri, hatta kategorileri korumak istiyorsanız, bunu yapmanın hızlı bir yoludur:

import numpy as np
import pandas as pd
df = pd.DataFrame({1: [1, 2, 3], 2: [4, 5, 6]})
number_repeats = 50
new_df = df.reindex(np.tile(df.index, number_repeats))

-1
import numpy as np
x=np.array([1,2,3])
y=np.multiply(np.ones((len(x),len(x))),x).T
print(y)

verim:

[[ 1.  1.  1.]
 [ 2.  2.  2.]
 [ 3.  3.  3.]]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.