MATLAB'da bir matrisin her satırına / sütununa bir işlevi nasıl uygulayabilirim?


106

Örneğin, diyerek bir vektördeki her öğeye bir işlev uygulayabilir v + 1veya işlevi kullanabilirsiniz arrayfun. For döngüsü kullanmadan bir matrisin her satırı / sütunu için bunu nasıl yapabilirim?

Yanıtlar:


73

Birçok yerleşik işlem gibi sumve prodhalihazırda satırlar veya sütunlar arasında çalışabilir, bu nedenle bundan yararlanmak için uyguladığınız işlevi yeniden düzenleyebilirsiniz.

Bu uygun bir seçenek değilse, bunu yapmanın bir yolu, satırları veya sütunları mat2cellveya kullanarak hücrelere toplamaktır num2cell, ardından cellfunelde edilen hücre dizisi üzerinde çalışmak için kullanmaktır .

Örnek olarak, bir matrisin sütunlarını toplamak istediğinizi varsayalım M. Bunu basitçe kullanarak yapabilirsiniz sum:

M = magic(10);           %# A 10-by-10 matrix
columnSums = sum(M, 1);  %# A 1-by-10 vector of sums for each column

Ve işte bunu daha karmaşık num2cell/ cellfunseçeneği kullanarak nasıl yapacağınız :

M = magic(10);                  %# A 10-by-10 matrix
C = num2cell(M, 1);             %# Collect the columns into cells
columnSums = cellfun(@sum, C);  %# A 1-by-10 vector of sums for each cell

17
Bu yaklaşımın herhangi bir özel durum için performansını basit bir döngü için test ederdim, bu da bir matrisi hücre dizisine dönüştürmekten daha hızlı olabilir. Test etmek için tic / tac sarma kullanın.
yuk

5
@yuk: Sanırım "tic / toc" demek istediniz. ;)
gnovice

4
@gnovice, belki yuk biraz sihir yaptı ve tak = toc atadı. true = falseGeçerli bir ifadenin olduğu bir dilde , bunu yapmanın bir yolu olduğuna eminim (:
chessofnerd

1
@Argyll: Hangi yaklaşımın daha verimli olduğunu belirlemek, ne tür bir işlevi uygulamak istediğinize, matrisin boyutuna, vb. Bağlı olacaktır. Kısacası, muhtemelen probleme bağlıdır. Aslında, bazen eski iyi bir for döngüsü en hızlı seçim olabilir.
gnovice

2
@gnovice, için bir düzenleme öneririm sum(M, 1). Yeni başlayanlar sum, keyfi boyutlu matrisler için bu şekilde kullanılabileceğini düşünebilir ve matris bir gün olduğunda şaşkına dönebilir 1-by-n.
Stewie Griffin

24

Daha belirsiz olan Matlab bsxfun işlevini isteyebilirsiniz . Matlab belgelerine göre, bsxfun "işlev tanıtıcısı tarafından belirtilen öğe-öğe ikili işlemi, tekil genişletme etkinleştirilmiş olarak A ve B dizilerine uygular."

@gnovice, yukarıda toplam ve diğer temel işlevlerin tekil olmayan ilk boyutta (yani birden fazla satır varsa satırlar, yalnızca bir satır varsa sütunlar veya daha düşük boyutların hepsinin boyuta sahipse daha yüksek boyutlarda == 1) çalıştığını belirtti. ). Ancak, bsxfun, (ve özellikle) kullanıcı tanımlı işlevler dahil olmak üzere herhangi bir işlev için çalışır.

Örneğin, bir A matrisiniz ve BEg satır vektörünüz olduğunu varsayalım, diyelim:

A = [1 2 3;
     4 5 6;
     7 8 9]
B = [0 1 2]

Bir C vektöründe A'daki tüm öğeleri karşılık gelen B sütununun üssüne döndüren bir power_by_col işlevi istiyorsunuz.

Yukarıdaki örnekten C, 3x3 bir matristir:

C = [1^0 2^1 3^2;
     4^0 5^1 6^2;
     7^0 8^1 9^2]

yani

C = [1 2 9;
     1 5 36;
     1 8 81]

Repmat kullanarak bunu kaba kuvvet yöntemiyle yapabilirsiniz:

C = A.^repmat(B, size(A, 1), 1)

Veya bunu, repmat adımını dahili olarak halleden bsxfun kullanarak klas bir şekilde yapabilirsiniz:

C = bsxfun(@(x,y) x.^y, A, B)

Yani bsxfun size bazı adımlar kazandırır (A'nın boyutlarını açık bir şekilde hesaplamanıza gerek yoktur). Bununla birlikte, bazı gayri resmi testlerimde, uygulanacak fonksiyon (yukarıdaki güç fonksiyonum gibi) basitse, repmat'ın kabaca iki kat daha hızlı olduğu ortaya çıkıyor. Bu yüzden basitlik mi yoksa hız mı istediğinizi seçmeniz gerekecek.


21

Bunun ne kadar verimli olduğu hakkında yorum yapamam ama işte bir çözüm:

applyToGivenRow = @(func, matrix) @(row) func(matrix(row, :))
applyToRows = @(func, matrix) arrayfun(applyToGivenRow(func, matrix), 1:size(matrix,1))'

% Example
myMx = [1 2 3; 4 5 6; 7 8 9];
myFunc = @sum;

applyToRows(myFunc, myMx)

Daha genel bir cevap verilir burada .
Wok

11

Alex'in cevabına dayanarak , işte daha genel bir işlev:

applyToGivenRow = @(func, matrix) @(row) func(matrix(row, :));
newApplyToRows = @(func, matrix) arrayfun(applyToGivenRow(func, matrix), 1:size(matrix,1), 'UniformOutput', false)';
takeAll = @(x) reshape([x{:}], size(x{1},2), size(x,1))';
genericApplyToRows = @(func, matrix) takeAll(newApplyToRows(func, matrix));

İşte iki işlev arasında bir karşılaştırma:

>> % Example
myMx = [1 2 3; 4 5 6; 7 8 9];
myFunc = @(x) [mean(x), std(x), sum(x), length(x)];
>> genericApplyToRows(myFunc, myMx)

ans =

     2     1     6     3
     5     1    15     3
     8     1    24     3

>> applyToRows(myFunc, myMx)
??? Error using ==> arrayfun
Non-scalar in Uniform output, at index 1, output 1.
Set 'UniformOutput' to false.

Error in ==> @(func,matrix)arrayfun(applyToGivenRow(func,matrix),1:size(matrix,1))'


4

Bu sorunun cevabının gelişen doğasına ek olarak, r2016b'den başlayarak, MATLAB bsxfunbirçok durumda ihtiyacı ortadan kaldırarak örtük olarak tekli boyutları genişletecektir .

Gönderen r2016b sürüm notlarına :

Örtülü Genişletme: Uzunluk 1'in boyutlarının otomatik olarak genişletilmesiyle dizilere eleman bazlı işlemler ve işlevler uygulayın

Örtük genişleme, skaler genişlemenin bir genellemesidir. Skaler genişletme ile, eleman bazlı işlemleri kolaylaştırmak için bir skaler başka bir diziyle aynı boyuta genişler. Örtük genişletme ile, burada listelenen eleman bazlı operatörler ve işlevler, diziler uyumlu boyutlara sahip olduğu sürece girdilerini aynı boyutta olacak şekilde örtük olarak genişletebilir. Her boyut için girişlerin boyut boyutları aynı ise veya bunlardan biri 1 ise, iki dizinin uyumlu boyutları vardır. Daha fazla bilgi için Temel İşlemler için Uyumlu Dizi Boyutları ve Matris İşlemlerine Karşı Diziye bakın.

Element-wise arithmetic operators+, -, .*, .^, ./, .\

Relational operators<, <=, >, >=, ==, ~=

Logical operators&, |, xor

Bit-wise functionsbitand, bitor, bitxor

Elementary math functionsmax, min, mod, rem, hypot, atan2, atan2d

Örneğin, bir A matrisindeki her sütunun ortalamasını hesaplayabilir ve ardından ortalama değerlerin vektörünü her sütundan A - ortalama (A) ile çıkarabilirsiniz.

Daha önce, bu işlevsellik bsxfun işlevi aracılığıyla mevcuttu. Artık bsxfun'un çoğu kullanımını örtük genişletmeyi destekleyen işlevlere ve işleçlere doğrudan çağrılarla değiştirmeniz önerilir. Bsxfun kullanımına kıyasla, örtük genişletme daha yüksek hız, daha iyi bellek kullanımı ve iyileştirilmiş kod okunabilirliği sunar.


2

Yukarıdaki cevapların hiçbiri benim için "kutunun dışında" işe yaramadı, ancak diğer cevapların fikirlerini kopyalayarak elde edilen aşağıdaki fonksiyon işe yarıyor:

apply_func_2_cols = @(f,M) cell2mat(cellfun(f,num2cell(M,1), 'UniformOutput',0));

Bir işlevi alır fve matrisin her sütununa uygular M.

Yani mesela:

f = @(v) [0 1;1 0]*v + [0 0.1]';
apply_func_2_cols(f,[0 0 1 1;0 1 0 1])

 ans =

   0.00000   1.00000   0.00000   1.00000
   0.10000   0.10000   1.10000   1.10000

1

Matlab'ın son sürümleri ile Tablo veri yapısını kendi avantajınıza kullanabilirsiniz. Bir 'rowfun' operasyonu bile var ama bunu yapmayı daha kolay buldum:

a = magic(6);
incrementRow = cell2mat(cellfun(@(x) x+1,table2cell(table(a)),'UniformOutput',0))

ya da burada eski Matlab sürümleri için tablo gerektirmeyen daha eski bir tane var.

dataBinner = cell2mat(arrayfun(@(x) Binner(a(x,:),2)',1:size(a,1),'UniformOutput',0)')

1

Kabul edilen cevap, önce hücrelere dönüştürmek ve ardından cellfuntüm hücreler üzerinde çalışmak için kullanmak gibi görünüyor . Spesifik uygulamayı bilmiyorum, ancak genel bsxfunolarak matris üzerinde işlem yapmak için kullanmanın daha verimli olacağını düşünürdüm. Temel olarak bsxfun, iki dizide bir işlem öğesi tek tek uygular. Dolayısıyla , bir dizi elde etmek için bir vektördeki n x 1her öğeyi bir vektördeki her öğeyle çarpmak isterseniz, şunu kullanabilirsiniz:m x 1n x m

vec1 = [ stuff ];    % n x 1 vector
vec2 = [ stuff ];    % m x 1 vector
result = bsxfun('times', vec1.', vec2);

Bu size result(i, j) girdisinin j'inci elemanı ile vec1çarpılan i'inci elemanı olacağı adı verilen matrisi verecektir vec2.

Her bsxfuntürlü yerleşik işlev için kullanabilir ve kendinizinkini ilan edebilirsiniz. Belgelerde birçok yerleşik işlevin bir listesi vardır, ancak temelde iki diziyi (vektör veya matris) bağımsız değişken olarak kabul eden herhangi bir işlevi adlandırabilir ve çalışmasını sağlayabilirsiniz.


-1

Bir matrisin satır toplamlarının nasıl hesaplanacağını ararken bu soruya / cevaba tökezledi.

Matlab'ın SUM işlevinin aslında belirli bir boyut için toplama desteğine sahip olduğunu eklemek isterim, yani iki boyutlu standart bir matris.

Yani sütun toplamlarını hesaplamak için şunları yapın:

colsum = sum(M) % or sum(M, 1)

ve satır toplamları için

rowsum = sum(M, 2)

Bahse girerim bu hem for döngüsü programlamaktan hem de hücrelere dönüştürmekten daha hızlıdır :)

Bütün bunlar SUM için matlab yardımında bulunabilir.


7
SUM'u belirli bir boyut boyunca uygulama yeteneği, bu sorunun orijinal cevabının ilk cümlesinde belirtilmiştir. Daha sonra yanıt, bir boyut seçme yeteneğinin işlevde zaten yerleşik olmadığı durumu ele almaya devam etti. Yine de, yerleşik boyut seçimi seçeneklerini kullanmanın - mevcut olduklarında - hemen hemen her zaman for döngüsünden veya hücrelere dönüştürmekten daha hızlı olduğu konusunda haklısınız.
cjh

Doğru, ancak yukarıdaki yanıt beni matlab belgelerine geri gönderdi, çünkü tüm bu hayalperestliğe ihtiyacım yoktu, bu yüzden sadece paylaşmak ve basit çözüme ihtiyaç duyan diğerlerini aramadan kurtarmak istedim.
nover

-2

Satırlarınızın uzunluğunu biliyorsanız, şöyle bir şey yapabilirsiniz:

a=rand(9,3);
b=rand(9,3); 
arrayfun(@(x1,x2,y1,y2,z1,z2) line([x1,x2],[y1,y2],[z1,z2]) , a(:,1),b(:,1),a(:,2),b(:,2),a(:,3),b(:,3) )

2
Bu cevabı gören herkese: Bunu yapmanın yolu bu değil! MATLAB'da hiçbir şey yapmanın yolu bu değil!
Stewie Griffin
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.