R: المصفوفات R والمصفوفات العادية

آخر تحديث: 2026-08-26

في الدرس السابق، تعرفنا على المتجهات «الأحادية البعد». في هذا الدرس، سننتقل إلى مفاهيم «ثنائية الأبعاد» و«متعددة الأبعاد» — المصفوفات والمصفوفات المصفوفية. تُعد المصفوفات أساس تحليل البيانات (فجداول بيانات Excel، ووحدات البكسل في الصور، وأوزان الشبكات العصبية كلها مصفوفات)، لذا دعونا نتأكد من فهمنا الكامل لها في هذا الدرس.

يُعد «جوهر» المصفوفات هو عائلة الدوال apply() — فهي تتيح لنا إجراء العمليات حسب الصف أو العمود أو البعد دون الحاجة إلى كتابة حلقات. وهنا تكمن ميزة لغة R في كونها أكثر إيجازًا من لغة Python.

1. ما ستتعلمه



2. قصة محضر

(1) المشكلة: تجميع الدرجات عبر مواد دراسية متعددة

شياو تشاو هو مسؤول الشؤون الأكاديمية. وفيما يلي كشوف الدرجات لخمسة طلاب في ثلاث مقررات دراسية:

TEXT 📖 للعرض فقط
       Mathematics  Chinese Language  English
Alice     85    78    92
Bob     72    88    80
Charlie     90    85    87
Diana     65    70    75
Eve     95    92    88

احسب: ① المجموع الكلي لدرجات كل طالب؛ ② متوسط الدرجات لكل مادة؛ ③ حدد الطالب الذي حصل على أعلى درجة في مادة الرياضيات.

لو كنت ستكتب هذا باستخدام صيغ Excel، فسيستغرق الأمر وقتًا طويلاً جدًّا؛ أما لو كنت ستكتبه بلغة Python، فسيتعين عليك استخدام حلقات متداخلة—

(2) الحل باستخدام لغة R

R
# 5x3 Matrix
scores <- matrix(c(85, 78, 92,
                   72, 88, 80,
                   90, 85, 87,
                   65, 70, 75,
                   95, 92, 88),
                 nrow = 5, byrow = TRUE)
colnames(scores) <- c("Mathematics", "Chinese Language", "English")
rownames(scores) <- c("Alice", "Bob", "Charlie", "Diana", "Eve")

# 1. Each Student's Total Score(Sum in One Line)
row_sums <- apply(scores, 1, sum)

# 2. Average per subject(Calculate the average for a column)
col_means <- apply(scores, 2, mean)

# 3. Find the highest score in math
top_math <- which.max(scores[, "Mathematics"])

خمس أسطر من التعليمات البرمجية لحل ثلاث مهام. هذه هي قوة المصفوفات ودالة apply.



3. جوهر المصفوفات: المتجهات ثنائية الأبعاد

(1) التحويل من المتجهات إلى المصفوفات

100%
graph LR
    A["One-dimensional vector c 1,2,3,4,5,6"] --> B["reshape into 2x3 Matrix"]
    B --> C["1 2 3 / 4 5 6"]
    B --> D["1 4 / 2 5 / 3 6"]
    
    style A fill:#cce5ff
    style B fill:#fff3cd
R
# One-dimensional vector
v <- 1:6
v
# [1] 1 2 3 4 5 6

# Convert to 2 row 3 List of Matrices
m <- matrix(v, nrow = 2, ncol = 3)
m
#      [,1] [,2] [,3]
# [1,]    1    3    5
# [2,]    2    4    6

(2) الخصائص الأربع الأساسية للمصفوفات

الخاصية المعنى مثال
dim(m) متجه الأبعاد dim(m)c(2, 3)
nrow(m) رقم السطر nrow(m)2
ncol(m) عدد الصفوف ncol(m)3
length(m) العدد الإجمالي للعناصر length(m)6
R
m <- matrix(1:6, nrow = 2)

dim(m)        # [1] 2 3
nrow(m)       # [1] 2
ncol(m)       # [1] 3
length(m)     # [1] 6  ← Total Number of Elements


4. matrix(): إنشاء مصفوفة

(1) قواعد النحو الأساسية

R
matrix(data, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL)

(2) 4 طرق للإبداع

R
# 1. Provide the data directly + Number of rows and columns
m1 <- matrix(1:6, nrow = 2)
#      [,1] [,2] [,3]
# [1,]    1    3    5   ← Fill by column by default
# [2,]    2    4    6

# 2. byrow = TRUE(Fill by Row)
m2 <- matrix(1:6, nrow = 2, byrow = TRUE)
#      [,1] [,2] [,3]
# [1,]    1    2    3
# [2,]    4    5    6

# 3. Add row and column names
m3 <- matrix(1:6, nrow = 2, byrow = TRUE,
            dimnames = list(c("row1", "row2"), c("colA", "colB", "colC")))
#     colA colB colC
# row1   1   2   3
# row2   4   5   6

# 4. Specify only nrow,ncol Automatic Inference
m4 <- matrix(1:6, nrow = 3)  # 3 row 2 col
#      [,1] [,2]
# [1,]    1    4
# [2,]    2    5
# [3,]    3    6
⚠️ ملاحظة: byrow = FALSE هو الإعداد الافتراضي (الملء حسب العمود). في معظم الحالات، نرغب في الملء حسب الصف (طالب واحد في كل صف/سجل واحد)، لذا يجب عليك تحديد byrow = TRUE صراحةً.

(3) إضافة تسميات للأعمدة والصفوف (لتسهيل القراءة)

R
m <- matrix(1:6, nrow = 2, byrow = TRUE)
rownames(m) <- c("Alice", "Bob")
colnames(m) <- c("Mathematics", "Chinese Language", "English")
m
#     Mathematics Chinese Language English
# Alice   1    2    3
# Bob   4    5    6


5. الوصول إلى عناصر المصفوفة

(1) 3 طرق للوصول

الطريقة الصيغة الغرض
[i, j] الصف i، العمود j عنصر واحد
[i, ] السطر i السطر بأكمله
[, j] العمود j العمود بأكمله
[i, "col_name"] عمود في الصف i حسب الاسم
R
m <- matrix(1:9, nrow = 3, byrow = TRUE,
            dimnames = list(c("Alice", "Bob", "Charlie"),
                          c("Mathematics", "Chinese Language", "English")))
m
#     Mathematics Chinese Language English
# Alice   1    2    3
# Bob   4    5    6
# Charlie   7    8    9

# A single element
m[2, 3]            # [1] 6
m["Bob", "English"]  # [1] 6

# Entire row
m[1, ]             # Mathematics 1 Chinese Language 2 English 3
m["Alice", ]        # Ibid.

# Align
m[, 1]             # Alice 1 Bob 4 Charlie 7
m[, "Mathematics"]        # Ibid.

(2) الفهرس المنطقي

R
# Find the math scores > 5 students
m[m[, "Mathematics"] > 5, ]
#     Mathematics Chinese Language English
# Bob   4 ...   ← Will not be selected
# Charlie   7    8    9


6. rbind/cbind: دمج المصفوفات

100%
graph TB
    A["Matrix A 3x2"] --> C["rbind Concatenate by row"]
    B["Matrix B 2x2"] --> C
    C --> D["New Matrix 5x2"]
    
    E["Matrix A 3x2"] --> F["cbind Concatenate by Column"]
    G["Matrix B 3x2"] --> F
    F --> H["New Matrix 3x4"]
    
    style A fill:#cce5ff
    style B fill:#cce5ff
    style E fill:#d4edda
    style G fill:#d4edda
R
a <- matrix(1:6, nrow = 3, byrow = TRUE)
b <- matrix(7:12, nrow = 3, byrow = TRUE)

# Concatenate by row(Sum of Rows)
rbind(a, b)
#      [,1] [,2]
# [1,]    1    2
# [2,]    3    4
# [3,]    5    6
# [4,]    7    8
# [5,]    9   10
# [6,]   11   12

# Concatenate by Column(Sum of a Series)
cbind(a, b)
#      [,1] [,2] [,3] [,4]
# [1,]    1    2    7    8
# [2,]    3    4    9   10
# [3,]    5    6   11   12
⚠️ ملاحظة: يتطلب rbind(a, b) وجود ncol(a) == ncol(b)؛ ويتطلب cbind(a, b) وجود nrow(a) == nrow(b)، وإلا فسيحدث خطأ.



7. سلسلة الدوال apply (الجوهر)

(1) لماذا نحتاج إلى apply؟

تعتبر الحلقات في لغة R بطيئة جدًّا، لكن apply تتيح لنا إجراء العمليات صفًّا تلو الآخر أو عمودًا تلو الآخر دون الحاجة إلى كتابة حلقات:

R
m <- matrix(1:9, nrow = 3)

# Find the sum of each row(No need for a loop)
apply(m, 1, sum)
# [1] 12 15 18

# Find the sum of each column
apply(m, 2, sum)
# [1] 12 15 18

(2) جوهر apply()

R
apply(X, MARGIN, FUN)
المعلمة المعنى القيم المحتملة
X مصفوفة/مجموعة مصفوفة / مجموعة
MARGIN البعد 1=الصف، 2=العمود، c(1,2)=الصف والعمود
FUN الوظيفة المراد تطبيقها sum mean max function(x) ...
R
# 1=row(Process by row),2=col(Process by Column)
apply(m, 1, mean)   # Average per line
apply(m, 2, max)    # Maximum per column

# Custom Functions
apply(m, 1, function(x) max(x) - min(x))  # Range per row

(3) الوظائف الخمس في عائلة apply

الوظيفة المدخلات المخرجات الاستخدامات الشائعة
apply() المصفوفات/المصفوفات المتجهات/المصفوفات العمليات على الصفوف/الأعمدة
lapply() القوائم/المصفوفات القوائم معالجة القوائم
sapply() القوائم/المتجهات المتجهات/المصفوفات lapply المبسط
tapply() المتجهات + المجموعات المصفوفات إحصائيات المجموعات
mapply() متعدد المتجهات قائمة/متجه دالة متعددة الحجج

(4) lapply() مقابل sapply()

R
# lapply Back to List
numbers <- list(a = 1:3, b = 4:6, c = 7:9)
result_l <- lapply(numbers, sum)
# $a 6
# $b 15
# $c 24

# sapply Return Vector(More commonly used)
result_s <- sapply(numbers, sum)
#  a  b  c
#  6 15 24
💡 نصيحة: استخدم sapply() أولاً — فهو أكثر ملاءمةً لإرجاع المتجهات. أما lapply() فيُستخدم بشكل أكثر شيوعًا في مسارات البرمجة الوظيفية.

(5) الإحصاءات المجمعة في دالة tapply()

R
# 5 Students 3 Course Grades, grouped by "Gender"
scores <- c(85, 78, 92, 72, 88, 80, 90, 85, 87, 65, 70, 75, 95, 92, 88)
gender <- c("M", "F", "M", "M", "F", "F", "M", "M", "F", "M", "F", "M", "F", "M", "F")

# Calculate the average by gender
tapply(scores, gender, mean)
#   F   M 
# 84.6 81.5
💡 نصيحة: يُستخدم tapply() بشكل شائع للغاية عند إجراء «إحصائيات المجموعات» — لكن استخدام dplyr::group_by() | summarise() في المرحلة التالية سيكون أكثر أناقة.

(6) mapply() — دالة متعددة الحجج

R
# Sum the corresponding elements of two vectors
mapply(function(a, b) a + b, 1:3, 10:12)
# [1] 11 13 15


8. المصفوفات: التوسعات متعددة الأبعاد

R
# 2x3x4 a three-dimensional array
arr <- array(1:24, dim = c(2, 3, 4))

# 1st 2x3 Matrix
arr[, , 1]
#      [,1] [,2] [,3]
# [1,]    1    3    5
# [2,]    2    4    6

# apply Supports multidimensional operations
apply(arr, c(1, 2), mean)  # Regarding No. 3 Find the average
💡 نصيحة: نادرًا ما تُستخدم المصفوفات في التطوير الفعليdata.frame (المرحلة التالية) وarray (الصور/الفيزياء) هما النهجان السائدان للتعامل مع البيانات متعددة الأبعاد.



9. عمليات المصفوفات (الجبر الخطي)

العملية الصيغة الوصف
تبديل t(m) من صف إلى عمود
ضرب المصفوفات m1 %*% m2 ضرب المصفوفات في الجبر الخطي
الضرب العنصري m1 * m2 الضرب العنصري المقابل
المعكوس solve(m) المصفوفة المعكوسة
المجموع (الصفوف/الأعمدة) rowSums(m) / colSums(m) المجموع السريع
R
m <- matrix(1:4, nrow = 2)
#      [,1] [,2]
# [1,]    1    3
# [2,]    2    4

# Transpose
t(m)
#      [,1] [,2]
# [1,]    1    2
# [2,]    3    4

# Matrix Multiplication (use m %*% m)
m %*% m
#      [,1] [,2]
# [1,]    7   15
# [2,]   10   22

# Inverse
solve(m)
#      [,1] [,2]
# [1,]   -2  1.5
# [2,]    1 -0.5


10. مثال كامل: تحليل شامل لنص محاضرة

فيما يلي مثال على مسار عمل كامل يجمع بين جميع المصفوفات ووظائف apply الواردة في هذا الدرس.

▶ مثال: تحليل شامل لدرجات الفصل

R 📖 للعرض فقط
# ============================================
# Comprehensive Analysis of Class Performance
# Features:5 Student 3 A Comprehensive Analysis of the Course Grade Matrix
# ============================================

# 1. Create a Grade Matrix(Fill by Row:One student per line)
scores <- matrix(c(
  85, 78, 92,   # Alice
  72, 88, 80,   # Bob
  90, 85, 87,   # Charlie
  65, 70, 75,   # Diana
  95, 92, 88    # Eve
), nrow = 5, byrow = TRUE)

# Add row and column names
rownames(scores) <- c("Alice", "Bob", "Charlie", "Diana", "Eve")
colnames(scores) <- c("Mathematics", "Chinese Language", "English")

cat("=== Grade Matrix ===\n")
print(scores)

# 2. Each Student's Total Score(Sum by Row)
cat("\n=== Student's Total Score ===\n")
row_totals <- apply(scores, 1, sum)
print(row_totals)

# 3. Average per subject/Highest/Lowest(Tally by Column)
cat("\n=== Statistics by Subject ===\n")
col_stats <- apply(scores, 2, function(x) {
  c(mean = round(mean(x), 2),
    max = max(x),
    min = min(x),
    sd = round(sd(x), 2))
})
print(col_stats)

# 4. Average score per student(Calculate the average by row)
cat("\n=== Average Student Score ===\n")
row_means <- apply(scores, 1, mean)
print(round(row_means, 2))

# 5. Identify the student with the highest math score
top_math <- which.max(scores[, "Mathematics"])
cat("\nHighest Score in Math:", rownames(scores)[top_math], "(", max(scores[, "Mathematics"]), "min)\n")

# 6. Identify the student with the highest total score
top_total <- which.max(row_totals)
cat("Highest Total Score:", rownames(scores)[top_total], "(", max(row_totals), "min)\n")

# 7. Find a single subject < 70 students(Using Logical Indexes)
fail <- scores < 70
cat("\nFailed Courses(< 70):\n")
print(scores)
cat("\nDid I fail?(TRUE = Fail):\n")
print(fail)

# 8. Overall Ranking
cat("\n=== Overall Ranking(Sort by total score in descending order)===\n")
ranking <- order(row_totals, decreasing = TRUE)
result <- data.frame(
  Ranking = 1:5,
  Name = rownames(scores)[ranking],
  Total Score = row_totals[ranking],
  Average = round(row_totals[ranking] / 3, 2)
)
print(result)
43 سطر من الكود المنطقي (تجاوز الحد 40, للعرض فقط)

النتائج المتوقعة (مقتطف):

TEXT 📖 للعرض فقط
=== Grade Matrix ===
    Mathematics Chinese Language English
Alice   85   78   92
Bob   72   88   80
Charlie   90   85   87
Diana   65   70   75
Eve   95   92   88

=== Student's Total Score ===
Alice Bob Charlie Diana Eve
255  240  262  210  275

=== Average Student Score ===
Alice   Bob   Charlie   Diana   Eve
85.00  80.00  87.33  70.00  91.67

=== Overall Ranking(Sort by total score in descending order)===
  Ranking Name Total Score Average
1   1 Eve  275 91.67
2   2 Charlie  262 87.33
3   3 Alice  255 85.00
4   4 Bob  240 80.00
5   5 Diana  210 70.00


❓ أسئلة شائعة

س ما الفرق بين byrow = TRUE و FALSE؟
ج matrix(1:6, nrow=2, byrow=FALSE) (الافتراضي) يُملأ حسب الأعمدة: 1 3 5 / 2 4 6؛ byrow=TRUE يُملأ حسب الصفوف: 1 2 3 / 4 5 6. في سيناريوهات علم البيانات، تُملأ البيانات دائمًا تقريبًا حسب الصفوف (صف واحد لكل عينة).
س كيف أختار بين apply() وحلقة for؟
ج استخدم apply() كلما أمكن ذلك — فحلقات R أبطأ بمقدار 10 إلى 100 مرة. استخدم apply(m, 1, fun) بدلاً من «التكرار حسب الصف»، وapply(m, 2, fun) بدلاً من «التكرار حسب العمود».
س tapply() كيف يتم استخدام هذا في المشاريع العملية؟
ج tapply(x, group, fun) لإجراء «إحصاءات مجمعة» بسرعة — التجميع حسب الجنس، والمنطقة، والشهر، وما إلى ذلك. ومع ذلك، في المرحلة التالية، يُعد استخدام dplyr::group_by() \| summarise() نهجًا أكثر أناقة؛ حيث يُشكل tapply الأساس لذلك.

📖 ملخص


📝 تمارين

  1. المشكلة الأساسية: أنشئ مصفوفة 4×4 تحتوي على عناصر تتراوح قيمها بين 1 و16، يتم ملؤها صفًا تلو الآخر، مع تسميات الصفوف والأعمدة c("A","B","C","D") وc("X","Y","Z","W") على التوالي. اطبع المصفوفة وتأكد من صحة تسميات الصفوف والأعمدة.

  2. المسألة الأساسية: استخدم apply() لحساب مجاميع الصفوف ومجاميع الأعمدة ومتوسطات الصفوف والقيم القصوى للأعمدة للمصفوفة الواردة في المسألة السابقة.

  3. تمرين أساسي: استخدم rbind() وcbind() لدمج مصفوفتين 3×3 (تقوم بإنشائهما بنفسك)، وتحقق من كيفية تغير عدد الصفوف والأعمدة.

  4. مشكلة متقدمة: قم بمحاكاة درجات 6 طلاب في 4 مقررات دراسية: ① استخدم apply() لحساب المجموع الكلي لدرجات كل طالب؛ ② استخدم apply() لحساب متوسط الدرجات لكل مقرر دراسي؛ ③ استخدم which.max() لتحديد اسم الطالب الذي حصل على أعلى درجة في كل مقرر دراسي؛ ④ استخدم order() لترتيب الطلاب.

  5. التحدي: اكتب برنامجًا نصيًّا لإجراء «تحليل متدرج» للدرجات الخاصة بـ 100 طالب في 5 مقررات دراسية: ① استخدم tapply() لحساب المعدل العام عن طريق التجميع حسب «الجنس»؛ ② حدد عدد الطلاب الذين حصلوا على 90 أو أكثر في مادة الرياضيات لكنهم رسبوا في مادة اللغة الإنجليزية (حصلوا على أقل من 60)؛ ③ احسب الانحراف المعياري لكل طالب في المقررات الخمسة (باستخدام apply() + دالة مخصصة).

Web-Tutorial.com

فريق Web-Tutorial التقني

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

100%