ما هي الطريقة الأكثر كفاءة/أنيقة لحذف العناصر من مصفوفة في MATLAB؟

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

  •  22-08-2019
  •  | 
  •  

سؤال

أريد حذف عدة قيم محددة من مصفوفة (إذا كانت موجودة).من المحتمل جدًا وجود نسخ متعددة من القيم في المصفوفة.

على سبيل المثال، فكر في مصفوفة N-by-2 intersections.إذا كانت أزواج القيم [a b] و [c d] موجودة كصفوف في تلك المصفوفة، أريد حذفها.

لنفترض أنني أريد حذف صفوف مثل [-2.0 0.5] و [7 7] في المصفوفة التالية :

intersections =

   -4.0000    0.5000
   -2.0000    0.5000
    2.0000    3.0000
    4.0000    0.5000
   -2.0000    0.5000

بحيث أحصل بعد الحذف على:

intersections = 

   -4.0000    0.5000
    2.0000    3.0000
    4.0000    0.5000

ما هي الطريقة الأكثر كفاءة/أنيقة للقيام بذلك؟

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

المحلول

جرب هذا الخط الواحد (أين أ هي مصفوفة التقاطع الخاص بك و ب هي القيمة المراد إزالتها):

A = [-4.0 0.5;
     -2.0 0.5;
      2.0 3.0;
      4.0 0.5;
     -2.0 0.5];
B = [-2.0 0.5];
A = A(~all(A == repmat(B,size(A,1),1),2),:);

ثم كرر السطر الأخير لكل جديد ب تريد إزالة.

يحرر:

...وإليك خيار آخر:

A = A((A(:,1) ~= B(1)) | (A(:,2) ~= B(2)),:);

تحذير: يتم استخدام الإجابات هنا بشكل أفضل في الحالات التي لا يُتوقع فيها وجود أخطاء صغيرة في الفاصلة العائمة (على سبيل المثال.بقيم صحيحة).كما لوحظ في هذا سؤال المتابعة, ، فإن استخدام عاملي التشغيل "==" و"~=" يمكن أن يتسبب في نتائج غير مرغوب فيها.في مثل هذه الحالات، يجب تعديل الخيارات المذكورة أعلاه لاستخدام العوامل العلائقية بدلاً من عوامل المساواة.على سبيل المثال، سيتم تغيير الخيار الثاني الذي أضفته إلى:

tolerance = 0.001;   % Or whatever limit you want to set
A = A((abs(A(:,1)-B(1)) > tolerance) | (abs(A(:,2)-B(2)) > tolerance),:);

مجرد حتى رؤساء سريع!=)


بعض التوقيت البدائي:

في حال كان أي شخص حقًا مهتمًا بالكفاءة، لقد قمت للتو ببعض التوقيت البسيط لثلاث طرق مختلفة للحصول على الفهرس الفرعي للمصفوفة (الخياران اللذان ذكرتهما أعلاه و فنفان خيار ستروماتش):

>> % Timing for option #1 indexing:
>> tic; for i=1:10000, index = ~all(A == repmat(B,size(A,1),1),2); end; toc;
Elapsed time is 0.262648 seconds.
>> % Timing for option #2 indexing:
>> tic; for i=1:10000, index = (A(:,1) ~= B(1)) | (A(:,2) ~= B(2)); end; toc;
Elapsed time is 0.100858 seconds.
>> % Timing for STRMATCH indexing:
>> tic; for i=1:10000, index = strmatch(B,A); end; toc;
Elapsed time is 0.192306 seconds.

كما ترون، فإن خيار STRMATCH أسرع من اقتراحي الأول، ولكن اقتراحي الثاني هو الأسرع بين الثلاثة.لاحظ مع ذلك أن خياراتي وخيارات Fanfan تفعل أشياء مختلفة قليلاً:تقوم خياراتي بإرجاع الفهارس المنطقية للصفوف إلى يحفظ, ، ويعيد Fanfan المؤشرات الخطية للصفوف إلى يزيل.ولهذا السبب يستخدم خيار STRMATCH النموذج:

A(index,:) = [];

بينما أستخدم النموذج:

A = A(index,:);

ومع ذلك، يمكن إلغاء الفهارس الخاصة بي لاستخدام النموذج الأول (فهرسة الصفوف إلى يزيل):

A(all(A == repmat(B,size(A,1),1),2),:) = [];    % For option #1
A((A(:,1) == B(1)) & (A(:,2) == B(2)),:) = [];  % For option #2

نصائح أخرى

والحل بسيط هنا هو أن ننظر إلى ضبط وظائف الأعضاء، أي setdiff، الاتحاد، وismember.

A = [-4  0.5;
   -2    0.5;
    2    3;
    4    0.5;
   -2    0.5];

B = [-2 .5;7 7];

وانظر ما ismember الحال مع صفائف اثنين. استخدام الخيار "الصفوف".

ismember(A,B,'rows')

ans =
     0
     1
     0
     0
     1

ومنذ نود أن حذف صفوف من A والتي هي أيضا في B، فقط تفعل هذا:

A(ismember(A,B,'rows'),:) = []

A = 
      -4          0.5
       2            3
       4          0.5

وحذار أن مجموعة الوظائف العضوية للبحث عن تطابق تام. الأعداد الصحيحة أو مضاعفات 1/2 مثل هم في تلبية هذا المطلب. إنها تتمثل بالضبط في النقطة العائمة حسابي في MATLAB.

وكان هذه الأرقام كانت أرقام النقطة العائمة الحقيقي، ويهمني أن يكون أكثر حذرا. هناك كنت قد استخدمت التسامح على الفرق. في هذه الحالة، قد يكون لديك حساب مصفوفة المسافة interpoint بين مجموعتين من الأرقام، وإزالة صف من A إلا إذا كانت تقع ضمن مسافة معينة من أحد الصفوف من B.

ويمكنك أيضا الاعتداء على وظيفة strmatch لتلائم الاحتياجات الخاصة بك: التعليمة البرمجية التالية يزيل كل أحداثا من صف محدد ب في مصفوفة A

A(strmatch(b, A),:) = [];

إذا كنت تحتاج إلى حذف أكثر من صف واحد، مثل جميع الصفوف من مصفوفة B، أعاد عليها:

for b = B'
   A(strmatch(b, A),:) = [];
end

ولست متأكدا عندما قدم هذه الوظيفة (باستخدام 2012b) ولكن يمكنك القيام به فقط:

setdiff(A, B, 'rows')
ans =

   -4.0000    0.5000
    2.0000    3.0000
    4.0000    0.5000

وبناء على:

A = [-4.0 0.5;
     -2.0 0.5;
      2.0 3.0;
      4.0 0.5;
     -2.0 0.5];
B = [-2.0 0.5];
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top