R: المصفوفات R والمصفوفات العادية
آخر تحديث: 2026-08-26
في الدرس السابق، تعرفنا على المتجهات «الأحادية البعد». في هذا الدرس، سننتقل إلى مفاهيم «ثنائية الأبعاد» و«متعددة الأبعاد» — المصفوفات والمصفوفات المصفوفية. تُعد المصفوفات أساس تحليل البيانات (فجداول بيانات Excel، ووحدات البكسل في الصور، وأوزان الشبكات العصبية كلها مصفوفات)، لذا دعونا نتأكد من فهمنا الكامل لها في هذا الدرس.
يُعد «جوهر» المصفوفات هو عائلة الدوال apply() — فهي تتيح لنا إجراء العمليات حسب الصف أو العمود أو البعد دون الحاجة إلى كتابة حلقات. وهنا تكمن ميزة لغة R في كونها أكثر إيجازًا من لغة Python.
1. ما ستتعلمه
- تُنشئ الدالة matrix() مصفوفة (يتم ملؤها بالصفوف أو الأعمدة)
- خصائص المصفوفة (dim، nrow، ncol، rownames، colnames)
- rbind/cbind: دمج المصفوفات
- تطبيق الدوال العائلية (apply/lapply/sapply/tapply/mapply)
- التوسعات متعددة الأبعاد لنوع البيانات
array - عمليات المصفوفات (التحويل
%*%، العكسsolve()) - تجربة عملية: إحصائيات النصوص
2. قصة محضر
(1) المشكلة: تجميع الدرجات عبر مواد دراسية متعددة
شياو تشاو هو مسؤول الشؤون الأكاديمية. وفيما يلي كشوف الدرجات لخمسة طلاب في ثلاث مقررات دراسية:
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
# 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) التحويل من المتجهات إلى المصفوفات
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
# 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 |
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) قواعد النحو الأساسية
matrix(data, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL)
(2) 4 طرق للإبداع
# 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) إضافة تسميات للأعمدة والصفوف (لتسهيل القراءة)
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 | حسب الاسم |
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) الفهرس المنطقي
# 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: دمج المصفوفات
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
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 تتيح لنا إجراء العمليات صفًّا تلو الآخر أو عمودًا تلو الآخر دون الحاجة إلى كتابة حلقات:
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()
apply(X, MARGIN, FUN)
| المعلمة | المعنى | القيم المحتملة |
|---|---|---|
X |
مصفوفة/مجموعة | مصفوفة / مجموعة |
MARGIN |
البعد | 1=الصف، 2=العمود، c(1,2)=الصف والعمود |
FUN |
الوظيفة المراد تطبيقها | sum mean max function(x) ... |
# 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()
# 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()
# 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() — دالة متعددة الحجج
# Sum the corresponding elements of two vectors
mapply(function(a, b) a + b, 1:3, 10:12)
# [1] 11 13 15
8. المصفوفات: التوسعات متعددة الأبعاد
# 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) |
المجموع السريع |
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 الواردة في هذا الدرس.
▶ مثال: تحليل شامل لدرجات الفصل
# ============================================
# 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)
النتائج المتوقعة (مقتطف):
=== 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 الأساس لذلك.📖 ملخص
- المصفوفة هي متجه ثنائي الأبعاد، في حين أن المصفوفة هي متجه متعدد الأبعاد؛
matrix()الإنشاء،array()التوسيع إلى أبعاد متعددة byrow = TRUEملء حسب الصف (المعيار المتبع في علم البيانات)،FALSE(الافتراضي) ملء حسب العمود- طريقة الوصول
m[i, j]/m[i, ]/m[, j]/m["row", "col"] rbind()الترتيب حسب الصف،cbind()الترتيب حسب العمود- تطبيق المجموعة:
apply()حسب البعد،lapply()قائمة → قائمة،sapply()قائمة → متجه،tapply()إحصائيات مجمعة،mapply()معلمات متعددة - عمليات المصفوفات:
t()التبادل،%*%ضرب المصفوفات،solve()معكوس المصفوفة،rowSums()colSums()الجمع السريع - استخدم
applyبدلاً من الحلقات: الحلقات في R أبطأ بـ 10 إلى 100 مرة؛ إذا كان بإمكانك استخدامapply، فلا تكتب حلقات
📝 تمارين
-
المشكلة الأساسية: أنشئ مصفوفة 4×4 تحتوي على عناصر تتراوح قيمها بين 1 و16، يتم ملؤها صفًا تلو الآخر، مع تسميات الصفوف والأعمدة
c("A","B","C","D")وc("X","Y","Z","W")على التوالي. اطبع المصفوفة وتأكد من صحة تسميات الصفوف والأعمدة. -
المسألة الأساسية: استخدم
apply()لحساب مجاميع الصفوف ومجاميع الأعمدة ومتوسطات الصفوف والقيم القصوى للأعمدة للمصفوفة الواردة في المسألة السابقة. -
تمرين أساسي: استخدم
rbind()وcbind()لدمج مصفوفتين 3×3 (تقوم بإنشائهما بنفسك)، وتحقق من كيفية تغير عدد الصفوف والأعمدة. -
مشكلة متقدمة: قم بمحاكاة درجات 6 طلاب في 4 مقررات دراسية: ① استخدم
apply()لحساب المجموع الكلي لدرجات كل طالب؛ ② استخدمapply()لحساب متوسط الدرجات لكل مقرر دراسي؛ ③ استخدمwhich.max()لتحديد اسم الطالب الذي حصل على أعلى درجة في كل مقرر دراسي؛ ④ استخدمorder()لترتيب الطلاب. -
التحدي: اكتب برنامجًا نصيًّا لإجراء «تحليل متدرج» للدرجات الخاصة بـ 100 طالب في 5 مقررات دراسية: ① استخدم
tapply()لحساب المعدل العام عن طريق التجميع حسب «الجنس»؛ ② حدد عدد الطلاب الذين حصلوا على 90 أو أكثر في مادة الرياضيات لكنهم رسبوا في مادة اللغة الإنجليزية (حصلوا على أقل من 60)؛ ③ احسب الانحراف المعياري لكل طالب في المقررات الخمسة (باستخدامapply()+ دالة مخصصة).