2012-01-06 32 views
6

Với p vectơ x1,x2,...,xp mỗi chiều d, cách tốt nhất để tính toán tensor/ngoài/Kruskal sản phẩm của họ (các p -array X với mục X[i1,i2,..ip] = x1[i1]x2[i2]...xp[ip]) là gì? Looping là tầm thường, nhưng ngu ngốc. Sử dụng lặp đi lặp lại các cuộc gọi đến outer hoạt động OK, nhưng dường như không giống như các giải pháp tối ưu (và sẽ nhận được chậm hơn như p tăng lên, rõ ràng) có cách nào tốt hơnOuter sản phẩm/tensor trong R

Edit:.?

tốt nhất hiện nay của tôi là

array(apply(expand.grid(x1, x2, x3), 1, prod), dim=rep(d, 3)) 

đó có ít nhất "cảm thấy tốt hơn" ...

Chỉnh sửa 2: Đáp lại @Dwin, đây là một ví dụ hoàn chỉnh

d=3 
x1 = 1:d 
x2 = 1:d+3 
x3 = 1:d+6 
array(apply(expand.grid(x1, x2, x3), 1, prod), dim=rep(d, 3)) 

, , 1 

    [,1] [,2] [,3] 
[1,] 28 35 42 
[2,] 56 70 84 
[3,] 84 105 126 

, , 2 

    [,1] [,2] [,3] 
[1,] 32 40 48 
[2,] 64 80 96 
[3,] 96 120 144 

, , 3 

    [,1] [,2] [,3] 
[1,] 36 45 54 
[2,] 72 90 108 
[3,] 108 135 162 
+0

Điều này có thể trả lời câu hỏi của bạn - http://stackoverflow.com/questions/6192848/how-to-generalize-outer-to-n-dimensions/6193836#6193836 –

+0

Câu trả lời được chấp nhận là khá chậm; nó có vẻ chậm hơn so với các cuộc gọi lặp đi lặp lại bên ngoài (không ngạc nhiên như thế nào nói chung nó là). Nhưng tôi nghĩ rằng có thể thứ hai có thể được điều chỉnh ... – MMM

+0

Tôi sẽ rất ngạc nhiên nếu giải pháp 'expand.grid' nhanh hơn giải pháp' bên ngoài'. –

Trả lời

5

Nó sẽ được khó khăn để đánh bại hiệu suất của outer. Điều này kết thúc lên làm một phép nhân ma trận được thực hiện bởi các thư viện BLAS.Kọi outer nhiều lần không quan trọng, kể từ cuộc gọi cuối cùng sẽ thống trị cả tốc độ lẫn trí nhớ. Ví dụ: đối với vectơ có độ dài 100, cuộc gọi cuối cùng chậm hơn 100 lần so với trước đó ...

Đặt cược tốt nhất của bạn để có hiệu suất tốt nhất ở đây là nhận thư viện BLAS tốt nhất cho R. Trình mặc định không phải là rất tốt. Trên Linux, bạn có thể dễ dàng cấu hình R để sử dụng ATLAS BLAS. Trên Windows thì khó hơn, nhưng có thể. Xem R for Windows FAQ.

# multiple outer 
mouter <- function(x1, ...) { 
    r <- x1 
    for(vi in list(...)) r <- outer(r, vi) 
    r 
} 

# Your example 
d=3 
x1 = 1:d 
x2 = 1:d+3 
x3 = 1:d+6 
mouter(x1,x2,x3) 

# Performance test 
x <- runif(1e2) 
system.time(mouter(x,x,x)) # 0 secs (less than 10 ms) 
system.time(mouter(x,x,x,x)) # 0.5 secs/0.35 secs (better BLAS) 

tôi thay thế Windows của tôi Rblas.dll với phiên bản DYNAMIC_ARCH của GOTO BLAS tại this place mà cải thiện thời gian 0,5-0,35 giây như đã thấy ở trên.

+0

Làm cho tinh thần. Tôi hầu như tự hỏi liệu có cái gì đó trong căn cứ tôi đã mất tích hay không, nhưng tôi đoán nó thực sự là một thứ đặc biệt. Cảm ơn. – MMM

+0

Thay vì tạo 'mouter', bạn có thể sử dụng' Reduce': 'Reduce ("% o% ", danh sách (x1, x2, x3))'. Đừng nghĩ rằng hiệu suất sẽ thay đổi nhiều. – James

+0

'/ ref:' Ước tính tốc độ tăng từ BLAS được tối ưu hóa có thể cao hơn một bậc: http://blog.felixriedel.com/2012/10/speed-up-r-by-using-a-different- blas-implementation / – isomorphismes

1

Bạn có thể sử dụng tensor gói.

Và cũng %o% chức năng

A <- matrix(1:6, 2, 3) 
D <- A %o% A 
+0

Vâng, '% o%' là chính xác 'bên ngoài (x, y, '*')' do đó sẽ không giúp được vấn đề tốc độ. Như mọi khi, :-) Tôi phải hỏi, "cái gì là Vấn đề bạn đang cố gắng giải quyết? "Có thể có một cách khác thông qua dữ liệu của bạn. –

+0

Tôi biết cách lấy sản phẩm bên ngoài của hai ma trận (hoặc hai vectơ); đó không phải là những gì tôi cần. nó không phải là ngay lập tức rõ ràng với tôi như thế nào nó sẽ giúp đỡ. – MMM

+0

@Carl Witthoft Mảng kết quả là (gần như) các pmf chung của một biến rời rạc đa biến.Tôi cần xấp xỉ pmf này, hoặc một cách để trả lại tất cả các mục của nó lớn hơn một số giá trị, và cũng là tổng của các mục. – MMM

1

tôi thấy mình tự hỏi nếu sản phẩm kronecker là những gì bạn muốn. Tôi không thể nói từ mô tả vấn đề của bạn chính xác những gì mong muốn, nhưng các yếu tố từ điều này trên một tập nhỏ các đối số là như nhau (mặc dù trong một sự sắp xếp khác với những gì được sản xuất bởi giải pháp Chalasani mà bạn đã chỉ trích là chậm:

kronecker(outer(LETTERS[1:2], c(3, 4, 5),FUN=paste), letters[6:8] ,FUN=paste) 
    [,1] [,2] [,3] 
[1,] "A 3 f" "A 4 f" "A 5 f" 
[2,] "A 3 g" "A 4 g" "A 5 g" 
[3,] "A 3 h" "A 4 h" "A 5 h" 
[4,] "B 3 f" "B 4 f" "B 5 f" 
[5,] "B 3 g" "B 4 g" "B 5 g" 
[6,] "B 3 h" "B 4 h" "B 5 h" 

Nếu bạn muốn sản phẩm, sau đó thay thế một trong hai prod hoặc "*". trong bất kỳ trường hợp cung cấp một bộ mẫu của vectơ và đầu ra mong muốn là một thực hành tốt nhất trong các câu hỏi đặt ra.

+0

Xin lỗi, tôi nghĩ rằng nó đã được rõ ràng từ câu hỏi rằng đầu ra phải là một mảng, không phải là một ma trận. Tôi đã thêm một ví dụ để làm rõ. Tất cả đầu vào của tôi là vectơ, vì vậy kronecker và bên ngoài là tương đương. Thay thế chức năng kronecker trong câu trả lời của bạn với một cuộc gọi khác đến bên ngoài là giải pháp ban đầu của tôi, nó trả về một mảng. – MMM

+0

Vâng, đó là lý do tôi đề cập đến sự sắp xếp khác nhau. Trường hợp sử dụng của bạn không được mô tả vì vậy tôi nghĩ rằng nó có thể đáp ứng. –

Các vấn đề liên quan