คุณสามารถใช้ฟังก์ชั่นทุกรายการในเวกเตอร์โดยกล่าวว่าตัวอย่างเช่นv + 1
, arrayfun
หรือคุณสามารถใช้ฟังก์ชั่น ฉันจะทำมันสำหรับทุกแถว / คอลัมน์ของเมทริกซ์โดยไม่ต้องใช้ for loop ได้อย่างไร
คุณสามารถใช้ฟังก์ชั่นทุกรายการในเวกเตอร์โดยกล่าวว่าตัวอย่างเช่นv + 1
, arrayfun
หรือคุณสามารถใช้ฟังก์ชั่น ฉันจะทำมันสำหรับทุกแถว / คอลัมน์ของเมทริกซ์โดยไม่ต้องใช้ for loop ได้อย่างไร
คำตอบ:
การดำเนินการในตัวจำนวนมากเช่น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
true = false
เป็นคำสั่งที่ถูกต้องฉันแน่ใจว่ามีวิธีที่คุณทำได้ (:
sum(M, 1)
ผมขอแนะนำให้ไปแก้ไข เริ่มต้นอาจจะคิดว่าสามารถใช้วิธีนี้ได้โดยพลการฝึกอบรมขนาดใหญ่และได้รับแล้วนิ่งงันเมื่อเมทริกซ์หนึ่งในวันนี้คือsum
1-by-n
คุณอาจต้องการที่คลุมเครือมากขึ้น Matlab ฟังก์ชั่นbsxfun จากเอกสาร Matlab bsxfun "ใช้การดำเนินการไบนารีองค์ประกอบโดยองค์ประกอบที่ระบุโดย fun handle ฟังก์ชันกับอาร์เรย์ A และ B โดยเปิดใช้งานการขยายแบบซิงเกิลตัน"
@gnovice ระบุไว้ข้างต้นว่าผลรวมและฟังก์ชันพื้นฐานอื่น ๆ ทำงานในมิติข้อมูลที่ไม่ใช่ซิงเกิลตันแรกอยู่แล้ว (เช่นแถวถ้ามีมากกว่าหนึ่งแถวคอลัมน์ถ้ามีเพียงแถวเดียวหรือมีมิติที่สูงกว่าหากมิติที่ต่ำกว่าทั้งหมดมีขนาด == 1 ). อย่างไรก็ตาม bsxfun ใช้งานได้กับฟังก์ชันใด ๆ รวมถึง (และโดยเฉพาะ) ฟังก์ชันที่ผู้ใช้กำหนดเอง
ตัวอย่างเช่นสมมติว่าคุณมีเมทริกซ์ A และเวกเตอร์แถว BEg สมมติว่า:
A = [1 2 3;
4 5 6;
7 8 9]
B = [0 1 2]
คุณต้องการฟังก์ชัน power_by_col ซึ่งส่งกลับเวกเตอร์ C องค์ประกอบทั้งหมดใน A เป็นพลังของคอลัมน์ที่เกี่ยวข้องของ B
จากตัวอย่างข้างต้น C คือเมทริกซ์ 3x3:
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)
จากคำตอบของ Alexนี่คือฟังก์ชั่นทั่วไปเพิ่มเติม:
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 / อ้างอิง / table.html ) มากกว่าการฝึกอบรม
การเพิ่มลักษณะการพัฒนาของคำตอบสำหรับคำถามนี้โดยเริ่มจาก r2016b MATLAB จะขยายมิติข้อมูลเดี่ยวโดยปริยายทำให้ไม่จำเป็นต้องมีbsxfun
ในหลาย ๆ กรณี
การขยายโดยนัย: ใช้การดำเนินการและฟังก์ชันที่ชาญฉลาดขององค์ประกอบกับอาร์เรย์ที่มีการขยายขนาดความยาว 1 โดยอัตโนมัติ
การขยายโดยนัยเป็นลักษณะทั่วไปของการขยายสเกลาร์ ด้วยการขยายสเกลาร์สเกลาร์จะขยายให้มีขนาดเท่ากับอาร์เรย์อื่นเพื่ออำนวยความสะดวกในการดำเนินการตามองค์ประกอบ ด้วยการขยายโดยปริยายตัวดำเนินการและฟังก์ชันที่ชาญฉลาดขององค์ประกอบที่ระบุไว้ในที่นี้สามารถขยายอินพุตให้มีขนาดเท่ากันได้โดยปริยายตราบเท่าที่อาร์เรย์มีขนาดที่เข้ากันได้ อาร์เรย์สองอาร์เรย์มีขนาดที่เข้ากันได้ถ้าสำหรับทุกมิติขนาดของอินพุตเหมือนกันหรือหนึ่งในนั้นคือ 1 ดูขนาดอาร์เรย์ที่เข้ากันได้สำหรับการดำเนินการขั้นพื้นฐานและการดำเนินการอาร์เรย์เทียบกับเมทริกซ์สำหรับข้อมูลเพิ่มเติม
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 - mean (A)
ก่อนหน้านี้ฟังก์ชันนี้พร้อมใช้งานผ่านฟังก์ชัน bsxfun ตอนนี้ขอแนะนำให้คุณแทนที่การใช้ bsxfun ส่วนใหญ่ด้วยการเรียกโดยตรงไปยังฟังก์ชันและตัวดำเนินการที่รองรับการขยายโดยปริยาย เมื่อเทียบกับการใช้ bsxfun การขยายโดยนัยให้ความเร็วที่เร็วขึ้นการใช้หน่วยความจำที่ดีขึ้นและการอ่านโค้ดที่ดีขึ้น
ไม่มีคำตอบใดที่ "นอกกรอบ" สำหรับฉันอย่างไรก็ตามฟังก์ชันต่อไปนี้ได้มาจากการคัดลอกแนวคิดของคำตอบอื่น ๆ ได้ผล:
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
ด้วย 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)')
คำตอบที่ได้รับการยอมรับดูเหมือนจะแปลงเป็นเซลล์ก่อนแล้วจึงใช้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
ขัดแย้ง (ฉัน j) รายการจะเป็นองค์ประกอบที่ i ของคูณด้วยองค์ประกอบของvec1
jthvec2
คุณสามารถใช้bsxfun
กับฟังก์ชันในตัวได้ทุกประเภทและคุณสามารถประกาศของคุณเองได้ เอกสารประกอบมีรายการฟังก์ชันในตัวมากมาย แต่โดยพื้นฐานแล้วคุณสามารถตั้งชื่อฟังก์ชันใด ๆ ที่รับอาร์เรย์สองอาร์เรย์ (เวกเตอร์หรือเมทริกซ์) เป็นอาร์กิวเมนต์และทำให้ทำงานได้
สะดุดกับคำถาม / คำตอบนี้ในขณะที่ค้นหาวิธีคำนวณผลรวมแถวของเมทริกซ์
ฉันแค่อยากจะเพิ่มว่าจริงๆแล้วฟังก์ชัน SUM ของ Matlab รองรับการหาผลรวมสำหรับมิติที่กำหนดนั่นคือเมทริกซ์มาตรฐานที่มีสองมิติ
ดังนั้นในการคำนวณผลรวมคอลัมน์ให้ทำ:
colsum = sum(M) % or sum(M, 1)
และสำหรับผลรวมแถวก็ทำ
rowsum = sum(M, 2)
เดิมพันของฉันคือเร็วกว่าทั้งการเขียนโปรแกรมสำหรับลูปและการแปลงเป็นเซลล์ :)
ทั้งหมดนี้สามารถพบได้ในวิธีใช้ matlab สำหรับ SUM
หากคุณทราบความยาวของแถวคุณสามารถสร้างสิ่งนี้ได้:
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) )