كيف يمكنني تطبيق دالة على كل صف/عمود في المصفوفة في MATLAB؟

StackOverflow https://stackoverflow.com/questions/2307249

سؤال

يمكنك تطبيق دالة على كل عنصر في المتجه بالقول، على سبيل المثال، v + 1, أو يمكنك استخدام الوظيفة arrayfun.كيف يمكنني القيام بذلك لكل صف/عمود في المصفوفة دون استخدام حلقة؟

هل كانت مفيدة؟

المحلول

العديد من العمليات المدمجة مثل sum و prod قادرون بالفعل على العمل عبر الصفوف أو الأعمدة ، لذلك قد تكون قادرًا على إعادة صياغة الوظيفة التي تتقدم بها للاستفادة من هذا.

إذا لم يكن هذا خيارًا قابلاً للتطبيق ، فإن إحدى الطرق للقيام بذلك هي جمع الصفوف أو الأعمدة إلى خلايا باستخدامها mat2cell أو num2cell, ، ثم استخدام cellfun للعمل على صفيف الخلية الناتج.

على سبيل المثال ، دعنا نقول أنك تريد تلخيص أعمدة المصفوفة M. يمكنك القيام بذلك ببساطة باستخدام sum:

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

وإليك كيف ستفعل هذا باستخدام أكثر تعقيدًا num2cell/cellfun اختيار:

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

نصائح أخرى

قد ترغب في المزيد من وظيفة MATLAB الغموض BSXFUN. من وثائق MATLAB ، يطبق BSXFUN "العملية الثنائية العنصر على حدة المحددة من قبل Function Confere Fun إلى المصفوفات A و B ، مع تمكين توسع Singleton."

ذكرت Gnovice أعلاه أن SUM وغيرها من الوظائف الأساسية تعمل بالفعل على البعد الأول غير Singleton (أي ، الصفوف إذا كان هناك أكثر من صف واحد ، أو أعمدة إذا كان هناك صف واحد فقط ، أو أبعاد أعلى إذا كانت الأبعاد السفلية لها حجم == 1 ). ومع ذلك ، يعمل BSXFUN لأي وظيفة ، بما في ذلك (وخاصة) وظائف محددة من قبل المستخدم.

على سبيل المثال ، دعنا نقول أن لديك مصفوفة A و ROW متجه BEG ، دعنا نقول:

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

تريد وظيفة power_by_col التي تعود في ناقل C جميع العناصر في A إلى قوة العمود المقابل لـ B.

من المثال أعلاه ، C عبارة عن مصفوفة 3 × 3:

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

بمعنى آخر،

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

يمكنك القيام بذلك طريقة القوة الغاشمة باستخدام repmat:

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

أو يمكنك القيام بذلك بالطريقة الأنيقة باستخدام BSXFUN ، والتي تعتني داخليًا بخطوة Repmat:

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

لذا فإن BSXFUN يوفر لك بعض الخطوات (لا تحتاج إلى حساب أبعاد A) بشكل صريح. ومع ذلك ، في بعض الاختبارات غير الرسمية الخاصة بي ، اتضح أن RepMAT هو حوالي ضعف سرعة إذا كانت الوظيفة المراد تطبيقها (مثل وظيفة الطاقة الخاصة بي ، أعلاه) بسيطة. لذلك ستحتاج إلى اختيار ما إذا كنت تريد البساطة أو السرعة.

لا يمكنني التعليق على مدى كفاءة هذا ، ولكن إليك حل:

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)

بناء على إجابة أليكس, ، إليك وظيفة أكثر عامة:

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));

فيما يلي مقارنة بين وظيفتين:

>> % 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))'

من أجل الاكتمال/الاهتمام ، أود أن أضيف أن MATLAB لديه وظيفة تتيح لك العمل على البيانات لكل صف بدلاً من عنصر. يدعي rowfun (http://www.mathworks.se/help/matlab/ref/rowfun.html) ، لكن "المشكلة" الوحيدة هي أنه يعمل الجداول (http://www.mathworks.se/help/matlab/ref/table.html) عوضا عن المصفوفات.

إضافة إلى الطبيعة المتطورة للإجابة على هذا السؤال، بدءًا من r2016b، سوف يقوم MATLAB بتوسيع الأبعاد المفردة ضمنيًا، مما يلغي الحاجة إلى bsxfun في كثير من الحالات.

من ملاحظات الإصدار r2016b:

التوسع الضمني:قم بتطبيق العمليات والوظائف المتعلقة بالعناصر على المصفوفات مع التوسيع التلقائي لأبعاد الطول 1

التوسع الضمني هو تعميم للتوسع العددي.مع التوسع العددي ، يتوسع العددية لتكون بنفس حجم مجموعة أخرى لتسهيل العمليات الحكيمة.من خلال التوسع الضمني ، يمكن للمشغلين والوظائف المذكورة هنا توسيع مدخلاتهم ضمنيًا لتكون بنفس الحجم ، طالما أن المصفوفات لها أحجام متوافقة.تحتوي صفائفان على أحجام متوافقة إذا كانت أحجام الأبعاد للمدخلات هي نفسها أو واحدة منها هي 1.انظر أحجام الصفيف المتوافقة للعمليات الأساسية و Array Vs.عمليات المصفوفة لمزيد من المعلومات.

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

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

Logical operators — &, |, xor

Bit-wise functions — bitand, bitor, bitxor

Elementary math functions — max, min, mod, rem, hypot, atan2, atan2d

على سبيل المثال ، يمكنك حساب متوسط ​​كل عمود في المصفوفة A ، ثم طرح متجه القيم المتوسطة من كل عمود بمتوسط ​​(A).

في السابق، كانت هذه الوظيفة متاحة عبر الدالة bsxfun.يوصى الآن باستبدال معظم استخدامات BSXFUN مع المكالمات المباشرة للوظائف والمشغلين التي تدعم التوسع الضمني.مقارنةً باستخدام BSXFUN ، يوفر التوسع الضمني سرعة أسرع ، واستخدام أفضل للذاكرة ، وتحسين قابلية القراءة من الكود.

مع الإصدارات الحديثة من MATLAB ، يمكنك استخدام بنية بيانات الجدول لصالحك. حتى أن هناك عملية "rowfun" لكنني وجدت أنه من الأسهل فقط القيام بذلك:

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

أو إليك واحدة أقدم كان لديّ لا تتطلب جداول ، لإصدارات MATLAB القديمة.

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

لم تعمل أي من الإجابات أعلاه "خارج الصندوق" بالنسبة لي ، ومع ذلك ، فإن الوظيفة التالية ، التي تم الحصول عليها عن طريق نسخ أفكار الإجابات الأخرى تعمل:

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

يستغرق وظيفة f ويطبقها على كل عمود من المصفوفة M.

على سبيل المثال:

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

يبدو أن الإجابة المقبولة هي التحويل إلى الخلايا أولاً ثم استخدامها cellfun للعمل على جميع الخلايا. لا أعرف التطبيق المحدد ، لكن بشكل عام أعتقد استخدامه bsxfun للعمل على المصفوفة سيكون أكثر كفاءة. أساسًا bsxfun يطبق عنصر التشغيل كل منهما عبر صفيفتين. لذلك إذا كنت ترغب في مضاعفة كل عنصر في n x 1 المتجه بواسطة كل عنصر في m x 1 المتجه للحصول على n x m صفيف ، يمكنك استخدام:

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

هذا سوف يعطيك المصفوفة تسمى result حيث سيكون إدخال (i ، j) عنصر ITH من vec1 مضروبة من قبل عنصر JTH من vec2.

يمكنك استخدام bsxfun بالنسبة لجميع أنواع الوظائف المدمجة ، ويمكنك إعلانك. تحتوي الوثائق على قائمة بالعديد من الوظائف المدمجة ، ولكن يمكنك في الأساس تسمية أي وظيفة تقبل صفيفتين (متجه أو مصفوفة) كوسائط والحصول عليها للعمل.

تعثر على هذا السؤال/الإجابة أثناء البحث عن كيفية حساب مبالغ الصفوف من المصفوفة.

أود فقط أن أضيف أن وظيفة مجموع MATLAB لديها في الواقع دعم لجمع بعد معين ، أي مصفوفة قياسية مع بعدين.

حتى لحساب مبالغ العمود تفعل:

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

وبالنسبة لمبالغ الصف ، ببساطة افعل

rowsum = sum(M, 2)

رهاني هو أن هذا أسرع من كلا البرمجة A للحلقة والتحويل إلى الخلايا :)

كل هذا يمكن العثور عليه في مساعدة MATLAB للمبلغ.

إذا كنت تعرف طول الصفوف الخاصة بك ، فيمكنك صنع شيء من هذا القبيل:

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) )
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top