Menu
flag Ar iconالعربيةdown icon

المصفوفات في R: ‏matrix() وcbind وrbind وحساب المصفوفات

كيف تبني المصفوفات بـ matrix() وcbind() وrbind()، وتفهرس الصفوف والأعمدة، وتفصل الضرب عنصرًا عنصرًا بالمعامل * عن ضرب المصفوفات الحقيقي بالمعامل %*%.

تحتوي هذه الصفحة على محررات قابلة للتشغيل - حرّر، شغّل، وشاهد النتيجة فوراً.

المصفوفة متجه ذو أبعاد

المصفوفة في R مستطيل من القيم - صفوف وأعمدة - تحمل فيه كل خلية النوع نفسه، وهو أرقام عادة. وهي تحت السطح متجه حرفيًا مُلحق به السمة dim، وهذا يفسر معظم سلوكها: نوع واحد في كل عناصرها، وحساب متجهي في كل موضع.

وتبني واحدة بإعادة تشكيل متجه عبر matrix():

ست قيم وصفان - وتستنتج R أن ثلاثة أعمدة مطلوبة. وتُبلغ dim() عن البعدين معًا بالصيغة 2 3؛ وتعطيهما nrow() وncol() كلًا على حدة.

وتفحّص المصفوفة المطبوعة بدقة: تسير القيم 1 2 في العمود الأول، ثم 3 4 في التالي. فـ R تملأ المصفوفات عمودًا عمودًا افتراضيًا. وإذا كانت بياناتك تُقرأ صفًا صفًا - وهي الطريقة التي يكتبها بها البشر عادة - فصرّح بذلك عبر byrow = TRUE:

والآن صار الصف الأول 1 2 3. ونسيان byrow = TRUE لا يطلق خطأ - بل يعطيك بصمت ترتيبًا يبدو منقولًا للأرقام نفسها، لذا اجعل فحص التخطيط المطبوع عادة كلما بنيت مصفوفة من قيم خام.

الفهرسة: ‏m[row, column]

تأخذ فهرسة المصفوفات موضعين داخل زوج واحد من الأقواس، الصف قبل الفاصلة والعمود بعدها - وكلاهما يعدّ من 1:

وترك موضع فارغًا يعني "جميعها": فالتعبير m[1, ] هو الصف الأول كاملًا، وm[, 2] هو العمود الثاني كاملًا. ولاحظ أن كليهما يعود متجهًا عاديًا - إذ تسقط R البعد الذي انكمش إلى الحجم 1. وهذا مريح في العمل التفاعلي وفخ في الشيفرة، لأن دالة تتوقع مصفوفة ستختنق بالمتجه. اطلب من R الإبقاء على الشكل عبر drop = FALSE:

تُبلغ dim() الآن عن 1 3 - فهي ما تزال مصفوفة. وكلما اقتطعت صفًا أو عمودًا مفردًا داخل دالة، فاكتب drop = FALSE؛ فالعلة التي يمنعها (شيفرة تعمل مع بيانات عريضة وتنهار مع بيانات ذات عمود واحد) علة بائسة في التعقب.

وتعمل الأقنعة المنطقية هنا أيضًا: فالتعبير m[m > 3] يعيد كل الخلايا التي تتجاوز 3، على هيئة متجه.

البناء باستخدام cbind() وrbind()

بدلًا من إعادة تشكيل متجه طويل واحد، يمكنك تجميع مصفوفة من قطع: إذ تربط cbind() المتجهات معًا أعمدةً، وتربطها rbind() صفوفًا. وتوسّع الدالتان نفساهما مصفوفة قائمة كذلك:

وتسافر الأسماء مع المتجهات: فقد استخدمت cbind() الاسمين heights وweights أسماءً للأعمدة تلقائيًا، وهو ما يبقي المصفوفة المطبوعة مقروءة. وتصر الدالتان على توافق الأطوال (مع إعادة التدوير للقيم بطول 1)؛ وربط متجه بطول 3 بمصفوفة ذات أربعة صفوف يطلق تحذيرًا.

ويمكن ضبط أسماء الأعمدة والصفوف مباشرة عبر colnames(m) <- ... وrownames(m) <- ...، وبعدها يمكنك الفهرسة بالاسم: ‏people[, "weights"].

الضرب عنصرًا عنصرًا * مقابل ضرب المصفوفات الحقيقي %*%

هذا هو التمييز الأهم في هذا المقال كله. فـ R تملك معاملَي ضرب اثنين للمصفوفات، وهما يحسبان أشياء مختلفة تمامًا:

  • التعبير a * a هو ضرب عنصر بعنصر: كل خلية مضروبة في الخلية المقابلة. فتصير القيم 1 2 3 4 هي 1 4 9 16، مرتبة في الشكل نفسه. وهذه ليست إلا عملية حسابية متجهية، أي المعامل * نفسه الذي تستخدمه مع المتجهات.
  • والتعبير a %*% a هو ضرب المصفوفات من الجبر الخطي - إذ تكون كل خلية في النتيجة صفًا من المصفوفة الأولى مضروبًا في عمود من الثانية ثم مجموعًا. وتعطي المدخلات نفسها القيم 7 10 15 22: أرقامًا مختلفة كليًا.

شغّل المقتطف وقارن المخرجين معًا؛ فرؤيتهما يختلفان على مدخلات متطابقة هي ما يرسّخ التمييز. وإذا كتبت * حيث تستدعي الرياضيات %*%، فلن تحذرك R - إذ تتوافق الأبعاد في الحالتين مع المصفوفات المربعة - وستحصل ببساطة على أرقام خاطئة. وفي شيفرة الإحصاء (مصفوفات التغاير، وجبر النماذج الخطية) تُعد هذه من العلل الصامتة الكلاسيكية.

وتنقل t() المصفوفة - أي تقلب الصفوف والأعمدة - وتظهر باستمرار بجوار %*% لأن ضرب المصفوفات يحتاج إلى تطابق الأبعاد الداخلية:

وللإكمال: تعكس solve(m) المصفوفة، ويعامل %*% المتجه بوصفه مصفوفة بعمود واحد. وهذا أقصى عمق يحتاجه معظم العمل مع البيانات.

ملخصات الصفوف والأعمدة

الجمع أو حساب المتوسط عبر الصفوف والأعمدة شائع إلى حد أن R تأتي بدوال مخصصة وسريعة له:

تطوي rowSums() كل صف إلى رقم واحد (6 15 هنا)، وتطوي colSums() كل عمود (5 7 9)، وتحسب صيغتا Means المتوسط بدلًا من الجمع. وفضّل هذه على الحلقات المصنوعة يدويًا بل وحتى على apply(m, 1, sum) - فهي أوضح وأسرع. أما للملخصات التي لا تغطيها هذه الأربع (كالقيمة العظمى لكل عمود مثلًا)، فإن عائلة apply هي الأداة العامة: ‏apply(m, 2, max).

مصفوفة أم إطار بيانات؟

كلاهما مستطيل، فأيهما تختار؟

  • المصفوفة: حين تكون كل خلية من النوع نفسه، وحين يهم الحساب. أي الحساب العددي، والجبر الخطي، وحسابات المسافات، والشبكات الشبيهة بالصور. والمصفوفات أخف وعملياتها أسرع بفضل ضمانة النوع الواحد تحديدًا.
  • إطار البيانات: حين تكون الأعمدة من أنواع مختلفة - أسماء بجوار أعمار بجوار رايات منطقية. وهذه هي البيانات الجدولية الواقعية، وهي ما تتوقعه كل دوال تحليل البيانات تقريبًا.

وثمة قاعدة جيدة: إذا كنت ستفتحه طبيعيًا في جدول بيانات بأعمدة مسماة ومختلطة، فهو إطار بيانات. أما إذا كان شبكة أرقام تنوي إجراء الجبر عليها، فهو مصفوفة. والتحويل بينهما سهل (as.matrix() وas.data.frame()) - لكن as.matrix() على إطار بيانات يحتوي أي عمود نصي تكره كل شيء على النوع النصي، فحوّل الأعمدة العددية وحدها.

ما تخرج به

  • المصفوفة متجه ذو أبعاد: نوع واحد في كل عناصرها، وتُبنى بـ matrix(data, nrow, ncol) - وتُملأ عمودًا عمودًا ما لم تمرر byrow = TRUE.
  • افهرس بالصيغة m[row, col]؛ والموضع الفارغ يعني "الكل"؛ وأضف drop = FALSE عند اقتطاع صفوف أو أعمدة مفردة داخل الشيفرة.
  • تجمّع cbind() وrbind() المصفوفات من متجهات أو توسّعان القائمة منها.
  • المعامل * عنصر بعنصر، والمعامل %*% ضرب مصفوفات حقيقي - مدخلات واحدة وأجوبة مختلفة ودون أي تحذير.
  • تتولى rowSums() وcolSums() وrowMeans() وcolMeans() الملخصات اليومية.

التالي: العوامل - كيف تمثل R البيانات الفئوية، والفخاخ المصاحبة لها.

الأسئلة الشائعة

كيف تنشئ مصفوفة في R؟

يعيد matrix(1:6, nrow = 2) تشكيل متجه إلى صفين وثلاثة أعمدة، ويملؤها عمودًا عمودًا. أضف byrow = TRUE لملئها صفًا صفًا بدلًا من ذلك. ويمكنك أيضًا تجميع مصفوفة من متجهات: فـ cbind() تلصقها أعمدةً، وrbind() تلصقها صفوفًا.

ما الفرق بين * و%*% في R؟

يضرب المعامل * عنصرًا عنصرًا - كل خلية في الخلية المقابلة، ويجب أن تتوافق الأبعاد. أما %*% فهو ضرب المصفوفات الحقيقي من الجبر الخطي (صفوف في أعمدة، فيجب أن تتطابق الأبعاد الداخلية). وهما يعطيان نتائج مختلفة تمامًا على المصفوفات نفسها، واستخدام * حيث قصدت %*% علة صامتة كلاسيكية.

كيف تحصل على صف واحد أو عمود واحد من مصفوفة في R؟

اترك الموضع الآخر فارغًا: فالتعبير m[1, ] هو الصف الأول، وm[, 2] هو العمود الثاني. ويعود كلاهما متجهًا عاديًا افتراضيًا. أضف drop = FALSE - كما في m[1, , drop = FALSE] - للإبقاء على النتيجة مصفوفة بصف واحد أو عمود واحد، وهو ما يهم حين تتوقع الشيفرة اللاحقة بعدين.

Coddy programming languages illustration

تعلّم البرمجة مع Coddy

ابدأ الآن