Matlab - ลบแถวและคอลัมน์ออกจากเมทริกซ์ที่มี 0

ฉันกำลังแก้ไขปัญหาเกี่ยวกับการโก่งตัวของลำแสง (มันไม่สนุกเกินไป :P)

ฉันต้องลดเมทริกซ์ความแข็งโดยรวมลงในเมทริกซ์ความแข็งของโครงสร้าง ฉันทำได้โดยการลบแถวและคอลัมน์ใด ๆ ออกจากเมทริกซ์ดั้งเดิมที่มี 0

ถ้าผมมีเมทริกซ์แบบนั้น (เรียกมันว่า K):

0   0   5   3   0   0
0   0   7   8   0   0
7   1   2   6   2   1
3   8   6   9   5   3
0   0   4   5   0   0
0   0   1   8   0   0 

เมทริกซ์รีดิวซ์ (เรียกมันว่า S) จะเป็นเพียงแค่

2   6
6   9

นี่คือสิ่งที่ฉันเขียนจนถึงตอนนี้เพื่อลดเมทริกซ์โกลบอล K ให้เป็นเมทริกซ์ความแข็ง S

S = K;

for i = 1:length(S(:,1))
    for j = 1:length(S(1,:))
        if  S(i,j) == 0
            S(i,:) = [];
            S(:,j) = [];
            break;
        end
    end
end

อย่างไรก็ตาม ฉันได้รับ "ดัชนีเกินขนาดเมทริกซ์" ในบรรทัดที่มีคำสั่ง "if" และฉันไม่แน่ใจว่าความคิดของฉันถูกต้องในวิธีที่ดีที่สุดในการลบแถวและคอลัมน์ทั้งหมด ขอขอบคุณข้อเสนอแนะใด ๆ !


person zZShort_CircuitZz    schedule 26.09.2014    source แหล่งที่มา


คำตอบ (4)


ง่าย:

S = K(all(K,2), all(K,1));
person Luis Mendo    schedule 26.09.2014
comment
ควันศักดิ์สิทธิ์ที่ราวกับเวทย์มนตร์! คงต้องดูฟังก์ชั่นทั้งหมดก่อนครับ.....ขอบคุณมาก! - person zZShort_CircuitZz; 27.09.2014
comment
ฮ่าๆๆๆ ฉันหัวเราะออกมาดังๆ กับความคิดเห็นของคุณจริงๆ ขอบคุณ! ดูสิ่งนี้ด้วย - person Luis Mendo; 27.09.2014
comment
@zZShort_CircuitZz ฉันได้ทำการแก้ไขแล้ว โปรดดูคำตอบที่อัปเดต - person Luis Mendo; 27.09.2014
comment
@zZShort_CircuitZz - all เป็นฟังก์ชันที่ตรวจสอบแถวทั้งหมดสำหรับคอลัมน์ใดคอลัมน์หนึ่งหรือคอลัมน์ทั้งหมดสำหรับแถวใดแถวหนึ่งในเมทริกซ์ของคุณเพื่อดูว่าค่า ทั้งหมด ไม่ใช่ศูนย์หรือไม่ หากเป็นกรณีนี้สำหรับแถว/คอลัมน์ใดคอลัมน์หนึ่ง ผลลัพธ์จะเป็น true / 1 มิฉะนั้น 0 all(K,2) ดูคอลัมน์ทั้งหมดสำหรับแต่ละแถว ในขณะที่ all(K,1) ดูแต่ละแถวสำหรับแต่ละคอลัมน์ ด้วยการทำ all(K,2), then all(K,1)` Luis กำลังกรองแถวที่มีศูนย์อย่างน้อยหนึ่งตัวออก จากนั้นจึงใช้ผลลัพธ์ระดับกลางนั้นเพื่อกรองคอลัมน์ที่มีศูนย์อย่างน้อยหนึ่งตัวออก - person rayryeng; 27.09.2014

สำหรับ nxn เมทริกซ์ หรือคุณสามารถลองใช้วิธีคูณเมทริกซ์ -

K=[
    0   0   5   3   2   0
    0   0   7   8   7   0
    7   1   6   6   2   1
    3   8   6   8   5   3
    0   0   4   5   5   0
    5   3   7   8   1   6]  %// Slightly different than the one in question

K1 = double(K~=0)
K2 = K1*K1==size(K,1)
K3 = K(K2)
S = reshape(K3,max(sum(K2,1)),max(sum(K2,2)))

เอาท์พุท -

S =
     6     6     2
     6     8     5
     7     8     1
person Divakar    schedule 26.09.2014
comment
แนวทางที่ดีมาก! การใช้ K1*K1 นั้นฉลาดมาก ประมาณ +0 คุณคิดว่ามันเร็วกว่า double() หรือแค่พิมพ์ง่ายกว่า :-) - person Luis Mendo; 27.09.2014
comment
@LuisMendo ไม่แน่ใจว่าอันไหนจะเร็วกว่า แต่ส่วนใหญ่แล้วความรู้สึกที่บอกว่า +0 จะเป็นเช่นนั้นและมันก็กะทัดรัดอยู่ดี ฉันคิดว่าควรหลีกเลี่ยงการเรียกใช้ฟังก์ชันจะดีกว่า - person Divakar; 27.09.2014
comment
@LuisMendo ทำการทดสอบไม่กี่ครั้งเพื่อเปรียบเทียบ double() กับ +0 double() ดูเหมือนว่าจะชนะด้วยการปรับปรุงเล็กน้อย 4%-8% สำหรับขนาดข้อมูลที่สูงขึ้น 1000x1000 ไม่เช่นนั้นฉันคิดว่าใครๆ ก็สามารถใช้อันใดอันหนึ่งได้ - person Divakar; 27.09.2014
comment
ดีแล้วที่รู้! ฉันคิดว่าฉันจะยึดติดกับ double() ต่อไป - person Luis Mendo; 27.09.2014

ปัญหาคือเมื่อคุณลบแถวหรือคอลัมน์บางแถวออก คุณไม่ควรเพิ่ม i หรือ j แต่ for loop ของ MATLAB จะอัปเดตโดยอัตโนมัติ อัลกอริธึมของคุณไม่สามารถจัดการกรณีเช่น:

0 1 0
1 1 1
1 1 1

มันจะลบเฉพาะคอลัมน์แรกเนื่องจากเงื่อนไขการแตกหัก ดังนั้นคุณต้องลบมันออก แต่จัดการดัชนีอย่างเหมาะสมด้วยวิธีใดวิธีหนึ่ง อีกวิธีหนึ่งอาจเริ่มจากการใช้ผลคูณของแถวและคอลัมน์ จากนั้นจึงตรวจสอบผลิตภัณฑ์เหล่านั้น และลบแถวและคอลัมน์ที่เกี่ยวข้องออกเมื่อองค์ประกอบของผลคูณเป็นศูนย์ ตัวอย่างการใช้งานใน MATLAB อาจเป็นดังนี้:

function [S] = stiff(K)
S = K;
% product of each row, rows(k) == 0 if there is a 0 in row k
rows = prod(S,2);
% product of each column, cols(k) == 0 if there is a 0 in column k
cols = prod(S,1);

ที่นี่เราคำนวณผลคูณของแต่ละแถวและแต่ละคอลัมน์

% firstly eliminate the rows
% row numbers in the new matrix
ii=1;
for i = 1:size(S,1),
    if rows(i) == 0,
        S(ii, :) = []; % delete the row
    else
        ii = ii + 1; % skip the row
    end
end

ที่นี่เราจะลบแถวที่มีศูนย์โดยการอัปเดตดัชนีด้วยตนเอง (สังเกต ii)

% handle the columns now
ii = 1;
for i = 1:size(S,2),
    if cols(i) == 0,
        S(:, ii) = []; % delete the row
    else
        ii = ii + 1; % skip the row
    end
end
end

ที่นี่เราใช้การดำเนินการเดียวกันกับคอลัมน์ที่เหลือ

person Mehmet Emre    schedule 26.09.2014

อีกวิธีหนึ่งที่ฉันแนะนำได้คือการแปลงเมทริกซ์ K เป็นเมทริกซ์เชิงตรรกะโดยที่อะไรก็ตามที่ไม่เป็นศูนย์จะเป็น 1 และ 0 มิฉะนั้น จากนั้นคุณจะต้องหาผลรวมของคอลัมน์ในเมทริกซ์นี้ จากนั้นตรวจสอบว่ามีคอลัมน์ใดไม่รวมกับจำนวนแถวที่คุณมีหรือไม่ คุณลบคอลัมน์เหล่านี้ออก จากนั้นหาผลรวมของแถวบนเมทริกซ์ระดับกลาง และตรวจสอบว่าแถวใดไม่เป็นผลรวมเท่ากับจำนวนคอลัมน์ที่คุณมี คุณลบแถวเหล่านี้ออกเพื่อให้เหลือเมทริกซ์สุดท้าย เช่นนี้:

Kbool = K ~= 0;
colsToRemove = sum(Kbool,1) ~= size(Kbool,1);
K(colsToRemove,:) = [];
rowsToRemove = sum(Kbool,2) ~= size(Kbool,2);
K(:,rowsToRemove) = []; 
person rayryeng    schedule 26.09.2014