برای مشاهده یافته ها از کلید Enter و برای خروج از کلید Esc استفاده کنید.

بردارها : بخش سوم

بردارها در R به اندازه ای جالب توجه هستند که نیاز است توضیحات بیشتری درباره آن ها ارائه شود. طی دو آموزش قبلی، به عملیاتی پرداخته شد که تنها بر روی یک بردار اعمال می شدند ولی در مواردی لازم است که بیش از یک بردار مورد بررسی قرار بگیرند.

ترکیب بردارها

اگرچه این فرایند چندان پیچیده نیست ولی اشاره به آن هم خالی از لطف نیست که می توان با استفاده از همان روشی که یک بردار را ایجاد می کنیم، چندین بردار را با هم ترکیب کنیم. البته، در انجام این فرایند به تبدیل نوع داده ها توجه داشته باشید که دچار مشکلات پیش بینی نشده نشوید.

num_vec <- c(101, 102, 103, 104, 105)
chr_vec <- c("A", "B", "C", "D")
sign_vec <- c("@", "#", "%")
mix_vec <- c(num_vec, chr_vec, sign_vec)
mix_vec 
#[1] "101" "102" "103" "104" "105" "A"   "B"   "C"   "D"   "@"   "#"   "%"

مقایسه بردارها

فرض کنید می خواهید دو بردار را با هم مقایسه کنید، یا می خواهید یک بردار کامل را با یک مقدار مشخص (یا اسکالر) مقایسه کنید. عملگرهای مقایسه (==، !=، <، >، <=، >=) می توانند مقایسه عنصر به عنصر دو بردار را انجام دهند. آنها همچنین می توانند عناصر یک بردار را با یک اسکالر مقایسه کنند. نتیجه چنین مقایسه ای، یک بردار از مقادیر منطقی است که در آن هر مقدار، نتیجه مقایسه یک عنصر با عنصر یا مقدار دیگر است. ممکن است این توضیحات کمی پیچیده به نظر بیاید ولی با مشاهده مثال ها، به سادگی آن پی خواهید برد.

ابتدا بیاید یک مرور سریع بر عملگرهای مقایسه داشته باشیم.

test_var1 <- 123
test_var2 <- 456
test_var1 < test_var2
# [1] TRUE
test_var1 > test_var2
# [1] FALSE
test_var1 <= test_var2
# [1] TRUE
test_var1 >= test_var2
# [1] FALSE
test_var1 == test_var2
# [1] FALSE
test_var1 == 122+1
# [1] TRUE

حالا بیاید با استفاده از عملگرهای معرفی شده، مقایسه بردارها را انجام دهیم.

test_vec1 <- c(12, 14, 16)
test_vec2 <- c(190, 14, 14)
test_vec1 == test_vec2
# [1] FALSE TRUE FALSE

همانگونه که مشاهده می کنید، مقایسه دو بردار به صورت نظیر به نظیر انجام شده و نتیجه هر مقایسه بین دو عضو متناظر در دو بردار در قالب یک مقدار منطقی نمایش داده شده است.

حالا بیاید شرایطی را فرض کنیم که دوبار طول یکسان نداشته باشند.

test_vec3 <- c(12, 15)
test_vec1 == test_vec3
# [1] TRUE FALSE FALSE
Warning message:
In test_vec1 == test_vec3:
longer object length is not a multiple of shorter object length

اگرچه در این حالت هم مقایسه انجام می شود ولی یک پیغام هشدار مبنی بر اینکه طول شی (بردار) بزگتر مضربی از شی (بردار) کوچکتر نیست، نمایش داده می شود. اگر به نتیجه این مقایسه توجه کنید، مشاهده می کنید که عملیات مقایسه برای دو عضو نخست صورت گرفته و از آنجاییکه عنصر سومی در بردار دوم وجود ندارد، نتیجه مقایسه نادرست تعیین شده است.

نکته: پیغام های هشدار (برخلاف پیغام های خطا) باعث توقف اجرای برنامه نمی شوند.

این آزمایش را می توانید با سایر عملگرهای مقایسه ای هم انجام دهید، به عنوان مثال:

test_vec1 >= test_vec3
# [1] TRUE FALSE TRUE
test_vec1 != test_vec3
# [1] FALSE TRUE TRUE

مقایسه یک بردار با یک مقدار معین (اسکالر) نیز که در موارد زیادی کاربرد پیدا می کنید هم پیچیده تر از مثال های پیش نیست:

test_val <- 12
test_vec1 == test_val
# [1] TRUE FALSE FALSE

اگر توجه کرده باشید، برای این مقایسه دیگر پیغام هشداری مبنی بر یکسان نبودن اندازه بردارها دریافت نمی کنیم چرا که R اسکالر را به اندازه طول بردار گسترش می دهد و سپس عملیات مقایسه انجام می شود.

در مواردی که تعدا عناصر بردارها زیاد است، بررسی اینکه مقایسه ها چه مقدار صحیح بوده اند یا نه، عملیاتی وقتگیر و حوصله سر بر است. همچنین در سناریوهای مختلفی ممکن است نیاز داشته باشیم که تنها موارد خاصی را بررسی کنیم، مانند اینکه آیا یک مورد (نا)صحیح در مقایسه های وجود داشته (به عنوان مثال برای شناسایی یک مورد نامعتبر در یک مجموعه داده ای به منظور رد یا تایید آن مجموعه) یا اطمینان حاصل کردن از اینکه نتیجه مقایسه برای تمامی عناصر، صحیح بوده است.

any(test_vec1 == test_vec3)
# [1]TRUE

any(test_vec1 == test_val)
# [1]TRUE

all(test_vec1 == test_val)
# [1]FALSE

all(test_vec1 == test_vec2)
# [1]FALSE

در مثال های بالا، تابع ()any وجود یک مورد صحیح را بررسی می کند و در صورت یافتن چنین موردی، نتیجه TRUE را بر می گرداند و در سوی دیگر ماجرا، تابع ()all در صورتی مقدار صحیح را برمی گرداند که عملیات مقایسه مورد نظر برای تمامی عناصر صحیح باشد. با توجه به عملکرد این دو تابع، در زمان استفاده از آن ها باید دقت بسیار زیادی انجام داد تا تطبیق آن ها با سناریوی مورد نظر رعایت شود در غیر اینصورت نتیجه حاصل شده از این توابع ممکن است ما را به تصمیم گیری اشتباه بکشاند.

تابع جالب توجه دیگر به منظور مقایسه بردارها، تابع ()identical است که یکسان بودن کامل دو بردار را بررسی می کند. به بیانی دیگر، زمانی خروجی این تابع TRUE است که تمامی عناصر دو بردار به صورت نظیر به نظیر با هم برابر باشند.

identical(test_vec1,test_vec3)
# FALSE

در مواردی این نیازمندی وجود دارد که تنها وجود عناصر یک بردار در بردار دیگر ( و نه یکسان بودن نظیر به نظیر آن ها) مورد بررسی قرار بگیرد. این عملیات به صورت زیر انجام می شود. توجه داشته باشید که برخلاف توابع و دستورهای مقایسه ای که پیشتر بررسی شدند، استفاده از این دستور جابه جا پذیر نیست و خروجی رابطه مستقیمی با ترتیب استفاده از بردارها دارد.

test_vec3 <- c(18,12,9,14,16,27)
test_vec1 %in% test_vec3
# [1] TRUE TRUE TRUE

test_vec3 %in% test_vec1
# [1] FALSE TRUE FALSE TRUE TRUE FALSE

شاید بتوان دستور ()setdiff را یک نسخه پیشرفته تر برای عملیات مثال قبل دانست، چرا که این تابع عناصری که در بردار نخست وجود دارند ولی در بردار دوم وجود ندارند را مشخص می کند.

vec_chr1 <- c("a", "b", "c")
vec_chr2 <- c("f", "b", "g", "c")
setdiff(vec_chr1,vec_chr2)
# [1] "a"

با استفاده از تابع ()intersect می توان یک گام بیشتر برداشت و آیتم هایی که در هر دو بردار مشترک هستند را مشخص و استخراج کرد.

intersect(test_vec1,test_vec3)
# [1] 12 14 16

محاسبات برداری

فرض کنید می خواهیم محاسبات برداری را به صورت یکباره بر روی کل یک بردار اعمال کنیم. برای انجام این کار، عملگرهای محاسباتی معمولی و مرسوم می توانند عملیات مورد نظر را بر روی تمامی عناصر بردارها انجام دهند. همچنین، بسیاری از توابع قابلیت اجرا بر روی یک بردار به صورت کلی را نیز دارند و نتیجه را به صورت بردار بر می گردانند.

به صورت کلی، دو مزیت بزرگ برای عملیات برداریدر R وجود دارد. نخستین و واضح ترین آن راحتی انجام فرایند است. عملیاتی که در زبان های دیگر نیاز به بکارگیری ساختارهای حلقه دارند، در R بی نیاز از حلقه و با یک خط کدنویسی انجام می شود. مزیت دوم، سرعت انجام عملیات است. اکثر عملیات برداری در R مستقیماً توسط کد C پیاده سازی می شوند، بنابراین آن ها به طور قابل توجهی سریعتر از کد R معادلی هستند که می توانید بنویسید.

در ادامه نحوه اجرای چنین عملیات هایی را از طریق چند مثال بررسی می کنیم.

test_vec4 <- c(10, 20, 30, 40)
test_vec5 <- c(1, 2, 3, 4)
test_vec4 + test_vec5
# [1] 11 22 33 44

test_vec4 * test_vec5
# [1] 10 40 90 160

توجه داشته باشید که طول نتیجه در این موارد برابر با طول بردارهای اصلی است. یعنی، اگر یک عملوند بردار و دیگری اسکالر باشد، این عمل بین هر عنصر بردار و مقدار اسکالر انجام می شود:

test_vec5 + 4
# [1] 5 6 7 8

حالت دیگری که ممکن است سوال برانگیز باشد، عدم تطابق طول بردارها در فرایند محاسبات است. در چنین مواردی، دو حالت متصور است: نخست اینکه طول بردار کوچکتر (با عناصر کمتر) مضربی از طول بردار بزرگتر باشد و حالت دوم اینکه چنین نباشد. در هر دو حالت، روال کار به این صورت است که عناصر بردار کوچکتر به صورت چرخشی در محاسبه با عناصر بردار بزرگتر مشارکت می کنند. به مثال زیر توجه کنید.

test_vec6 <- c(100, 200)
test_vec4 + test_vec6
# [1] 110 220 130 240

همانطور که مشاهده می کنید، از آنجاییکه بردار کوچکتر شامل دو عنصر و بردار بزرگتر دارای چهار عنصر است، به نوعی بردار کوچکتر هدایت کننده فرایند محاسبه شده است و ابتدا دو عنصر نخست بردار بزرگتر با عناصر بردار کوچکتر (که شامل دو آیتم هست) جمع می شوند و سپس عناصر بعدی بردار بزرگتر این فرایند را از ابتدا تکرار می کنند.

حالا، شرایطی را بررسی می کنیم که تعداد عناصر بردار کوچکتر مضربی از عناصر بردار بزرگتر نباشد.

test_vec7 <- c(100, 200, 300)
test_vec4 + test_vec7
# [1] 110 220 330 140
Warning message:
In test_vec4 + test_vec7 :
longer object length is not a multiple of shorter object length

فرایند محاسبه چرخشی عناصر بردار بزرگتر با عناصر بردار کوچکتر در این مورد هم انجام شد ولی از آنجاییکه این عناصر مضرب صحیحی از یکدیگر نیستند، این فرایند به صورت کامل انجام نشده و اگرچه خروجی تولید می شود ولی پیغام هشداری مبنی بر وجود یک ناهماهنگی نمایش داده می شود.