R: إطارات البيانات والعوامل في R
آخر تحديث: 2026-08-26
في الدروس التسعة السابقة، تعرفنا على المتجهات والمصفوفات والقوائم — ولكل منها حدودها. إطارات البيانات (data.frame) تحل كل هذه المشكلات: فهي سهلة القراءة مثل جدول بيانات Excel وفعالة مثل المصفوفة. في هذا الدرس، سنتعرف على «النجم» الحقيقي في لغة R — إطار البيانات.
تُعد إطارات البيانات ومكتبة «tidyverse» جوهر علم البيانات في لغة R. وابتداءً من هذا الدرس، سنبدأ رسميًّا في الغوص في عالم «تحليل البيانات باستخدام لغة R».
1. ما ستتعلمه
- الاختلافات بين
data.frame()وtibble() - إنشاء إطارات البيانات وعرضها والوصول إليها وتعديلها
- التصفية، التحديد، الترتيب
- متغير تصنيفي عاملي (factor)
- البدء في استخدام dplyr (الـ«خمسة عناصر الأساسية» لمعالجة البيانات)
- التجميع المجمَّع (group_by + summarise)
- التطبيق العملي: تحليل شامل لبيانات الموظفين
2. قصة تحويل ملف Excel إلى لغة R
(1) المشكلة: برنامج Excel غير قادر على التعامل مع ذلك
تحتوي جدول بيانات أبحاث السوق الخاص بـ «تشين» على 10,000 صف × 8 أعمدة:
EmployeesID Name Department Salary Years Performance Gender Start Date
2024001 Alice Data Department 15000 3 A M 2021-03-15
2024002 Bob Engineering Department 18000 5 A+ M 2019-08-20
...
حساب متوسط الرواتب حسب «القسم»، والفرز حسب «الأداء»، وتحديد الموظفين ذوي الرواتب المرتفعة... يستغرق ذلك 30 دقيقة في برنامج Excel، مع صيغ متداخلة لدرجة أن البرنامج قد يتعطل.
(2) الحل باستخدام لغة R
library(dplyr)
# 5 Code execution complete 5 An Analysis
df |>
group_by(Department) |>
summarise(Average Wage = mean(Salary), Number of people = n()) |>
arrange(desc(Average Wage)) |>
filter(Average Wage > 15000)
5 أسطر من التعليمات البرمجية بدلاً من 30 دقيقة في Excel. هذه هي قوة DataFrame + dplyr.
3. data.frame: «الشخصية الرئيسية» في لغة R
(1) ما هو إطار البيانات؟
graph TB
A["Data Frame data.frame"] --> B["Each column = 1 equal-length vectors"]
A --> C["Each line = 1 records"]
A --> D["Mixed Types(Each column is independent)"]
A --> E["The bottom layer is'A list of vectors of equal length'"]
style A fill:#fff3cd
style B fill:#cce5ff
style C fill:#d4edda
style D fill:#f8d7da
style E fill:#e1d4ff
إطار البيانات هو "قائمة من المتجهات ذات الطول المتساوي":
- كل عمود هو متجه (من نفس النوع)
- جميع الأعمدة متساوية في الطول
- يمكن أن تكون الأعمدة المختلفة من أنواع مختلفة (أعمدة رقمية + أعمدة أحرف + أعمدة منطقية)
(2) إنشاء إطار بيانات
# Methods 1:data.frame()(Basics R)
df <- data.frame(
name = c("Alice", "Bob", "Charlie"),
age = c(25, 30, 35),
score = c(95, 88, 92),
passed = c(TRUE, TRUE, TRUE)
)
print(df)
# name age score passed
# 1 Alice 25 95 TRUE
# 2 Bob 30 88 TRUE
# 3 Charlie 35 92 TRUE
# Methods 2:tibble(tidyverse Version,Recommendations)
# install.packages("tibble")
library(tibble)
df2 <- tibble(
name = c("Alice", "Bob", "Charlie"),
age = c(25, 30, 35),
score = c(95, 88, 92)
)
print(df2)
(3) data.frame مقابل tibble
| Feature | data.frame | tibble |
|---|---|---|
| طباعة | طباعة جميع الصفوف افتراضيًّا (قد يتسبب ذلك في تجميد النظام عند التعامل مع مجموعات بيانات كبيرة) | طباعة أول 10 صفوف + أنواع الأعمدة افتراضيًّا |
| اسم العمود | يدعم الأحرف الخاصة | فرض الصحة |
| مجموعة فرعية من مجموعة فرعية | df[, "col"] تُرجع متجهًا |
تُرجع دائمًا جدولًا (tibble) |
| الأداء | أبطأ | أسرع |
| سلسلة | التحويل إلى عامل بشكل افتراضي | الاحتفاظ بها كسلسلة |
# View Structure
str(df)
# 'data.frame': 3 obs. of 4 variables:
# $ name : chr "Alice" "Bob" "Charlie"
# $ age : num 25 30 35
# $ score : num 95 88 92
# $ passed: logi TRUE TRUE TRUE
# Summary Statistics
summary(df)
# name age score passed
# Length:3 Min. :25 Min. :88 Mode :logical
# Class :character 1st Qu.:27 Median :92 TRUE:3
# Mode :character Mean :30 Mean :91 NA's :0
# 3rd Qu.:32 3rd Qu.:93
# Max. :35 Max. :95
4. الوصول إلى DataFrames
(1) 4 طرق للوصول
| الطريقة | الصيغة | القيمة المرجعة | الغرض |
|---|---|---|---|
df[i, j] |
الصف i، العمود j | قيمة عددية/متجه/إطار بيانات | تركيبة الصف والعمود |
df[i, ] |
الصف i | DataFrame | الحصول على الصف |
df[, j] |
العمود j | متجه (R الأساسي) / إطار البيانات | استخراج العمود |
df$name |
حسب اسم العمود | متجه | الحصول على العمود |
df[["name"]] |
حسب اسم العمود | متجه | الحصول على العمود |
df <- data.frame(
name = c("Alice", "Bob", "Charlie"),
age = c(25, 30, 35),
score = c(95, 88, 92)
)
# Retrieve a single element
df[2, 3] # [1] 88
df[2, "score"] # [1] 88
# Select the entire row
df[1, ] # Entire row (Data Frame)
# name age score
# 1 Alice 25 95
# Round an entire column
df[, "age"] # Digital Vectors [1] 25 30 35
df$age # Ibid.
df[["age"]] # Ibid.
(2) الفهرس المنطقي (التصفية)
# Find the Fraction > 90 line
df[df$score > 90, ]
# name age score
# 1 Alice 25 95
# 3 Charlie 35 92
# Multiple conditions
df[df$age > 25 & df$score > 85, ]
(3) ⚠️ هام: استرجاع الأعمدة في لغة R الأساسية مقارنةً بـ tibble
# base R:Retrieve the column return vector
df[, "age"] # [1] 25 30 35 ← Digital Vectors
# tibble:Retrieve and return the column tibble
library(tibble)
tb <- as_tibble(df)
tb[, "age"] # ← tibble(1 row 1 col)
# Want to extract a vector from tibble: Use [[ ]] or $
tb[["age"]] # [1] 25 30 35 ← Digital Vectors
[, "col"] في tibble تلقائيًا إلى متجه. وهذه ميزة تصميمية «أمانية» — فهي تمنع النظام من تفسير إطارات البيانات الكبيرة خطأً على أنها متجهات، مما قد يتسبب في تجميد عملية الطباعة بأكملها.
5. تعديل إطار البيانات
(1) إضافة عمود
# Use $ to add
df$city <- c("Beijing", "Shanghai", "Guangzhou")
# Use transform()
df <- transform(df, bonus = score * 100)
# Use within() to reference column names
df <- within(df, level <- ifelse(score >= 90, "A", "B"))
print(df)
# name age score city bonus level
# 1 Alice 25 95 Beijing 9500 A
# 2 Bob 30 88 Shanghai 8800 B
# 3 Charlie 35 92 Guangzhou 9200 A
(2) تعديل الأعمدة
# Array Assignment
df$age <- df$age + 1
# Condition Modification
df$score[df$name == "Bob"] <- 90
(3) حذف عمود
# Assign NULL
df$bonus <- NULL
df$level <- NULL
(4) إضافة/حذف الصفوف
# Add a row: Use rbind
new_row <- data.frame(name = "Diana", age = 28, score = 85, city = "Shenzhen")
df <- rbind(df, new_row)
# Delete Row:Using Negative Indexes
df <- df[-1, ] # Delete 1st row
6. العامل: المتغير الفئوي
(1) لماذا نحتاج إلى العوامل؟
في لغة R، يُعد استخدام العوامل لتمثيل المتغيرات الفئوية (مثل «منخفض/متوسط/مرتفع») أكثر فعالية من استخدام متجهات الأحرف:
# Character vector(Disorder)
gender_char <- c("M", "F", "M", "F", "M")
# factor(Orderly + Finite values)
gender_factor <- factor(gender_char, levels = c("M", "F"))
gender_factor
# [1] M F M F M
# Levels: M F
(2) مزايا العوامل
graph TB
A["Character vector 'Low' 'Mid' 'High'"] --> B["factor factor<br/>+ levels Order<br/>+ Finite values<br/>+ Save memory"]
A --> C["Disadvantages: Cannot sort and compare"]
B --> D["Advantages: Can be compared for size<br/>Can be grouped in order<br/>Statistics/Knowing the Number of Categories in Modeling"]
style A fill:#f8d7da
style B fill:#d4edda
style D fill:#cce5ff
# Compare Sizes(Characters cannot,Factors can)
sizes <- factor(c("S", "L", "Mid", "L", "S"),
levels = c("S", "Mid", "L"),
ordered = TRUE)
sizes[1] < sizes[2] # TRUE <- Characters can't do that!
(3) العمليات الشائعة على العوامل
# View levels
levels(sizes)
# [1] "S" "Mid" "L"
# Frequency Count
table(sizes)
# sizes
# S Mid L
# 2 1 2
# Reorder
sizes <- factor(sizes, levels = c("L", "Mid", "S")) # Reverse the order
levels(sizes)
# [1] "L" "Mid" "S"
forcats (التي تمت مناقشتها في الدرس 11) للتعامل مع العوامل، لأنها أكثر أناقة من لغة R الأساسية.
(4) العوامل في إطار البيانات
# data.frame() Convert character strings to factors by default (This is a trap!)
df <- data.frame(
name = c("Alice", "Bob"), # Character vector
stringsAsFactors = FALSE # Disable Auto-Conversion(Recommendations)
)
str(df)
# $ name: chr "Alice" "Bob" ← Preserve characters
stringsAsFactors = FALSE بشكل افتراضي، لكن قد تستخدم الأكواد القديمة قيمة مختلفة. يُنصح بكتابة stringsAsFactors = FALSE صراحةً.
7. البدء في استخدام dplyr: العناصر الخمسة الأساسية لمعالجة البيانات
يُعد dplyr جوهر «tidyverse»؛ تغطي خمس دوال 80% من سيناريوهات معالجة البيانات:
(1) التركيب والتحميل
install.packages("dplyr")
library(dplyr)
(2) الدالة المكونة من خمسة أجزاء
| الوظيفة | الغرض | المكافئ في لغة SQL |
|---|---|---|
filter() |
تصفية الصفوف | WHERE |
select() |
تحديد العمود | SELECT |
mutate() |
إضافة/تعديل عمود | — |
arrange() |
فرز | ORDER BY |
summarise() |
إحصائيات إجمالية | GROUP BY |
(3) عامل التسلسل |>
# |> is R 4.1+'s "pipe symbol", Pass the result from the previous step to the next step
df |> filter(age > 25) |> select(name, age)
(4) تدريب عملي: معالجة بيانات الموظفين
# Prepare the data
employees <- tibble(
id = 2024001:2024010,
name = c("Alice", "Bob", "Charlie", "Diana", "Eve",
"Frank", "Grace", "Henry", "Ivy", "Jack"),
department = c("Data Department", "Engineering Department", "Data Department", "Product Department", "Engineering Department",
"Data Department", "Engineering Department", "Product Department", "Data Department", "Engineering Department"),
salary = c(15000, 18000, 16000, 20000, 17000,
15500, 19000, 21000, 16500, 17500),
years = c(3, 5, 4, 7, 4, 2, 6, 8, 3, 5),
performance = factor(
c("A", "A+", "B", "A+", "A", "B", "A", "A+", "B", "A"),
levels = c("B", "A", "A+"),
ordered = TRUE
)
)
# 1. filter:Screening Data Department Employees
data_dept <- employees |> filter(department == "Data Department")
# 2. select:Select a subset of columns
basic_info <- employees |> select(name, department, salary)
# 3. mutate:Add an "Annual Salary" column
employees <- employees |> mutate(annual_salary = salary * 12)
# 4. arrange:Sort by salary in descending order
ranked <- employees |> arrange(desc(salary))
# 5. summarise:By Department
dept_stats <- employees |>
group_by(department) |>
summarise(
Number of people = n(),
Average Wage = mean(salary),
Highest Salary = max(salary),
Total Annual Salary = sum(annual_salary)
) |>
arrange(desc(Average Wage))
print(dept_stats)
# # A tibble: 3 × 5
# department Number of people Average Wage Highest Salary Total Annual Salary
# <chr> <int> <dbl> <dbl> <dbl>
# 1 Product Department 2 20500 21000 492000
# 2 Engineering Department 4 17875 19000 858000
# 3 Data Department 4 15750 16500 756000
(5) مثال على تركيبة من 5 خطوات
# Comprehensive Example:Identify High-Performing, High-Earning Employees
top_talent <- employees |>
filter(performance %in% c("A+", "A")) |> # Performance Screening A+ or A
filter(salary > 16000) |> # ② Filter by High Salary
mutate(salary_level = ifelse(salary > 18000, "High", "Upper-middle")) |> # ③ Add Category
arrange(desc(salary)) |> # ④ Sort
select(name, department, salary, performance, salary_level) # ⑤ Select Column
print(top_talent)
# # A tibble: 3 × 5
# name department salary performance salary_level
# <chr> <chr> <dbl> <ord> <chr>
# 1 Henry Product Department 21000 A+ High
# 2 Diana Product Department 20000 A+ High
# 3 Bob Engineering Department 18000 A+ Upper-middle
8. مثال كامل: تحليل شامل لبيانات الموظفين
فيما يلي مثال على مسار عمل كامل يربط بين جميع المفاهيم التي تم تناولها في هذا الدرس.
▶ مثال: تحليل شامل لبيانات موظفي الشركة
# ============================================
# Comprehensive Analysis of Company Employee Data
# Features:Using a DataFrame + dplyr Comprehensive Analysis 10 employees
# ============================================
library(dplyr)
# 1. Prepare data
employees <- tibble(
id = 2024001:2024010,
name = c("Alice", "Bob", "Charlie", "Diana", "Eve",
"Frank", "Grace", "Henry", "Ivy", "Jack"),
department = c("Data Department", "Engineering Department", "Data Department", "Product Department", "Engineering Department",
"Data Department", "Engineering Department", "Product Department", "Data Department", "Engineering Department"),
salary = c(15000, 18000, 16000, 20000, 17000,
15500, 19000, 21000, 16500, 17500),
years = c(3, 5, 4, 7, 4, 2, 6, 8, 3, 5),
performance = factor(
c("A", "A+", "B", "A+", "A", "B", "A", "A+", "B", "A"),
levels = c("B", "A", "A+"),
ordered = TRUE
)
)
cat("=== Raw Data ===\n")
print(employees)
# 2. View Structure
cat("\n=== Data Structures ===\n")
str(employees)
# 3. Summary Statistics
cat("\n=== Abstract ===\n")
summary(employees)
# 4. By Department
cat("\n=== By Department ===\n")
dept_summary <- employees |>
group_by(department) |>
summarise(
Number of people = n(),
Average Wage = mean(salary),
Median Wage = median(salary),
Highest Salary = max(salary),
Minimum Wage = min(salary),
Average Length of Service = round(mean(years), 1)
) |>
arrange(desc(Average Wage))
print(dept_summary)
# 5. Identify High-Performing Employees (A+ or A)
cat("\n=== Employees with Outstanding Performance ===\n")
top_perf <- employees |>
filter(performance %in% c("A+", "A")) |>
arrange(desc(salary)) |>
select(name, department, salary, performance, years)
print(top_perf)
# 6. Add"Pay Grade"col
cat("\n=== Salary Grade Classification ===\n")
employees <- employees |>
mutate(
salary_level = factor(
ifelse(salary >= 18000, "High",
ifelse(salary >= 16000, "Mid", "Low")),
levels = c("Low", "Mid", "High"),
ordered = TRUE
),
annual_salary = salary * 12
)
# By Pay Grade
level_summary <- employees |>
group_by(salary_level) |>
summarise(Number of people = n(), Average Wage = mean(salary))
print(level_summary)
# 7. Identify the Best Employees (High Salary + High Performance + Senior)
cat("\n=== Top Employee (High Salary + Outstanding Performance + Senior) ===\n")
top_talent <- employees |>
filter(salary >= 17000, performance == "A+", years >= 5) |>
select(name, department, salary, years, performance, annual_salary)
print(top_talent)
النتائج المتوقعة (مقتطف):
=== By Department ===
# A tibble: 3 × 7
department Number of people Average Wage Median Wage Highest Salary Minimum Wage Average Length of Service
<chr> <int> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Product Department 2 20500 20500 21000 20000 7.5
2 Engineering Department 4 17875 17750 19000 17000 4.5
3 Data Department 4 15750 15750 16500 15000 3
=== Employees with Outstanding Performance ===
# A tibble: 6 × 5
name department salary performance years
<chr> <chr> <dbl> <ord> <dbl>
1 Henry Product Department 21000 A+ 8
2 Diana Product Department 20000 A+ 7
3 Bob Engineering Department 18000 A+ 5
4 Grace Engineering Department 19000 A 6
5 Eve Engineering Department 17000 A 4
6 Jack Engineering Department 17500 A 5
❓ أسئلة شائعة
ordered = TRUE) ② توفر مساحة الذاكرة (تخزن الترميزات الصحيحة فقط) ③ تتيح إجراء التحليل الإحصائي والنمذجة عندما يكون عدد الفئات معروفًا (مما يتجنب مشكلة «القيمة المجهولة»).📖 ملخص
- إطار البيانات هو «قائمة من المتجهات ذات الطول المتساوي»، حيث يكون لكل عمود نوع بيانات مميز، ويحتوي كل صف على سجل بيانات.
data.frame()أساسيات R،tibbleعالم tidyverse الحديث (موصى به للمشاريع الجديدة)- 4 روابط:
df[i, j]df$namedf[["name"]]df[, j] - العامل هو «متغير تصنيفي مرتب»؛ حيث تتحكم المستويات في الترتيب، مما يوفر مساحة الذاكرة
- مجموعة dplyr المكونة من خمس قطع:
filterselectmutatearrangesummarise group_by() | summarise()تنفيذ التجميع الجماعي؛|>رمز الأنبوب لربط عدة عمليات متتالية- يشير
mutateإلى العمود الذي تم إنشاؤه للتو (وهو ما لا يستطيعtransformالقيام به)، ولهذا السبب يحظىmutateبشعبية أكبر في tidyverse
📝 تمارين
-
تمرين أساسي: استخدم
data.frame()لإنشاء إطار بياناتstudents(6 طلاب × 4 أعمدة: الاسم/العمر/الدرجة/النجاح). اطبع إطاري البياناتstr()وsummary()، واطلع على جميع الأعمدة في الصف الثالث. -
المسألة الأساسية: حوّل العمود
nameمن المسألة السابقة إلىfactor(3 مستويات)، وقارن الفروق بينas.character()وas.numeric(). تحقق من أن العامل يدعم مقارنة القيم المطلقة (>). -
المسألة الأساسية: قم بتثبيت وتحميل
dplyr، ثم استخدمfilter()لتصفية الطلاب منscore > 85بناءً علىstudentsمن المسألة السابقة، وقم بفرزهم بترتيب تنازلي حسب الدرجات باستخدامarrange(). -
تمرين متقدم: استخدم
tibbleلإنشاء إطار بياناتsales(10 صفوف × 4 أعمدة: المنتج/المنطقة/المبلغ/التاريخ). ① استخدمmutate()لحساب مجموعdiscount = amount * 0.1؛ ② استخدمgroup_by(region) + summarise()لحساب إجمالي المبيعات لكل منطقة؛ ③ استخدمarrange(desc())لترتيب المناطق. -
التحدي: باستخدام بيانات محاكاة للموظفين (10 موظفين، 3 أقسام، الراتب/سنوات الخدمة/الأداء)، أكمل التحليل المكون من 7 خطوات: ① قم بتحميل dplyr ② احسب عدد الموظفين ومتوسط الراتب حسب القسم ③ حدد الموظفين ذوي الرواتب المرتفعة الذين تبلغ مدة خدمتهم 5 سنوات أو أكثر ④ استخدم
mutateلإضافة عمود للراتب السنوي ⑤ استخدمcase_when(أوifelse) للتصنيف حسب شرائح الرواتب ⑥ قم بالفرز حسب الأداء ⑦ اكتب في إطار بيانات جديدtop_employeesواحفظه كملف CSV (write.csv()).