ভে

ভেক্টর মধ্যে R

১টি অনুশীলনী

ভেক্টর সম্পর্কে

R-এ একটি vector (প্রকৃতপক্ষে একটি atomic vector) হলো একই type-এর মানের একটি সংগ্রহ: সাধারণত integer, numeric, character, logical; কদাচিৎ complex বা raw. এগুলো মেমোরিতে পরস্পর সংলগ্নভাবে সংরক্ষিত থাকে, অনেকটা C অ্যারের মতো।

মিশ্র ইনপুট দিলে R চুপচাপ সেগুলোকে একটি অভিন্ন টাইপে, সাধারণত character-এ, রূপান্তর করে ফেলে, যার ফলে অপ্রত্যাশিত ফলাফল আসতে পারে।

v <- c(2, 5.4, "txt")
v
#> [1] "2"   "5.4" "txt"
typeof(v)
#> [1] "character"

ভেক্টর তৈরি করা

সব মান আগে থেকেই থাকলে c() ব্যবহার করুন (এটি "concatenate"-এর সংক্ষিপ্ত রূপ):

x <- 10
v <- c(4, 7, x)

c() ফাংশনটি খুবই নমনীয়, আর ইনপুটে অন্য ভেক্টর বা রেঞ্জও থাকতে পারে। c() যেকোনো সংখ্যক ও যেকোনো ধরনের ইনপুট নিতে পারে, আর সেগুলোকে সমতল করে একটি ভেক্টরে পরিণত করে।

ভেক্টর যদি ছোট আকারে শুরু হয়ে রানটাইমে অনেক বেড়ে যায় (যেমন লুপে মান যোগ করা), তাহলে আগেই একটি লম্বা ভেক্টর বরাদ্দ করে রাখা অনেক দ্রুত হতে পারে, যেটি পরে আসল ডেটা দিয়ে ভরা যায়:

v <- vector(length = 100) 

এতে অবজেক্টটি কপি করার প্রয়োজন কমে যায়, যা লম্বা ভেক্টরের ক্ষেত্রে ধীরগতির ও অনেক মেমোরি খাওয়া একটি কাজ।

রেঞ্জ, সিকোয়েন্স, রিপিট

পরপর থাকা মানের রেঞ্জের জন্য (ক্রমে বাড়তে থাকা বা কমতে থাকা) আপনি : নোটেশন ব্যবহার করতে পারেন।

v <- 1:5 # equivalent to c(1, 2, 3, 4, 5)
w <- 10:7 # c(10, 9, 8, 7)

R-এ রেঞ্জ আলাদা কোনো টাইপ নয়, এটা শুধু ভেক্টর তৈরির একটি সংক্ষিপ্ত রূপ।

seq() ফাংশনটি আরও সূক্ষ্ম নিয়ন্ত্রণ দেয়:

# specify step size
seq(2, 11, by = 3) # c(2, 5, 8, 11)

# specify number of values, evenly-spaced
seq(2.5, 4, length.out = 5) # c(2.500, 2.875, 3.250, 3.625, 4.000) 

rep() ফাংশনটি দিয়ে সহজেই পুনরাবৃত্ত প্যাটার্ন তৈরি করা যায়:

count <- 3
rep(7, count)
#> [1] 7 7 7

rep(1:3, count)
#> [1] 1 2 3 1 2 3 1 2 3

rep(1:3, each = 2) # the "each" keyword is required in this case
#> [1] 1 1 2 2 3 3

কয়েকটি রেঞ্জ বিল্ট-ইন কনস্ট্যান্ট হিসেবে আগেই দেওয়া আছে:

letters  # LETTERS is the UPPERCASE equivalent
#> [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"

month.name
#> [1] "January"   "February"  "March"     "April"     "May"       "June"      "July"      "August"   
#> [9] "September" "October"   "November"  "December" 

month.abb
#> [1] "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"

গাণিতিক ক্রিয়া

ক্রিয়াগুলো স্বয়ংক্রিয়ভাবে ভেক্টরের প্রতিটি এলিমেন্টের উপর আলাদা আলাদা প্রয়োগ হয়। অন্য ভাষায় কমন লুপ, লিস্ট কম্প্রিহেনশন আর রিকার্শনের এখানে দরকার নেই, আর (পারফরম্যান্সের কারণে) সম্ভব হলে এগুলো এড়িয়ে চলা উচিত।

2 + 1:3     # c(3, 4, 5)
2 * 1:3     # c(2, 4, 6)
12 / 1:3    # c(12  6  4)
2 ^ (1:3)   # c(2, 4, 8) : exponentiation, operator precedence order here needs ()

ভেক্টরের জোড়াও কাজ করে, যেখানে এলিমেন্টগুলো জোড়ায় জোড়ায় বিবেচিত হয়:

v <- 1:3
w <- 5:7

v + w
#> [1]  6  8 10

v * w
#> [1]  5 12 21

v ^ w
#> [1]    1   64 2187

প্রথমে যতটা মনে হয়, এটি তার চেয়ে অনেক বেশি শক্তিশালী, আর পরের কনসেপ্টগুলোতে আরও অনেক কিছু ঘুরে দেখার থাকবে।

ভেক্টরের এলিমেন্ট অ্যাক্সেস করা

অনেক ভাষার মতোই বন্ধনীর ভেতরে ইনডেক্স ব্যবহার করা যায়:

v <- 4:7
v[2]
#> [1] 5
v[2:4]
#> [1] 5 6 7

তবে সাবধান: R ডিফল্টভাবে ১ থেকে শুরু করে ইনডেক্স গোনে। এটা বৈজ্ঞানিক ভাষাগুলোতে (Fortran, Matlab, Julia) কমন, কিন্তু C ও তার উত্তরসূরি অনেক ভাষার শূন্য-ভিত্তিক ইনডেক্সিং থেকে আলাদা।

উপরের উদাহরণের মতোই রেঞ্জ ব্যবহার করা যায়, আবার অত্যন্ত নমনীয় c() ফাংশনেও ব্যবহার করা যায়:

v <- c(4, 7, 10)
w <- c(2, v[2:3], 11) # c(2, 7, 10, 11)

vectors-কে (R-এর বেশিরভাগ জিনিসের মতোই) পরিবর্তনযোগ্য হিসেবে ব্যবহার করা যায়, আর একই রকম নমনীয় সিনট্যাক্স দিয়ে একটি বা একাধিক এলিমেন্টে মান লেখা যায়:

v <- 1:10
v[2] <- 42
v[4:6] <- c(11, 12, 13)
v
#> [1]  1 42  3 11 12 13  7  8  9 10

ঋণাত্মক ইনডেক্স

অন্য ভাষার সাথে পরিচিত প্রোগ্রামাররা হয়তো ভাবতে পারেন যে v[-1] দিয়ে ভেক্টরের শেষ এলিমেন্টটি পাওয়া যায়। ভুল! সেজন্য tail() ব্যবহার করুন।

v <- c(2, 4, 6) # defaults to last 6 entries
tail(v)
#> [1] 2 4 6
tail(v, n=1) # just the last entry
#> [1] 6

আসলে ঋণাত্মক ইনডেক্স হলো একটি এলিমেন্ট বাদ দেওয়ার উপায়:

v <- c(2, 4, 6)
v[-2]
#> [1] 2 6  # second element gone

এতে ভেক্টরটির একটি ছোট কপি রিটার্ন হয়। v নিজে অপরিবর্তিত থাকে।

ভেক্টরের শর্ত

একটি ভেক্টরে তুলনা প্রয়োগ করলে সমান দৈর্ঘ্যের একটি বুলিয়ান ভেক্টর রিটার্ন হয়। এটি all() আর any()-এর মতো ফাংশনের ভেতরে খুবই সুবিধাজনক হতে পারে:

v <- c(4, 7, 10)
v >= 6
#> [1] FALSE  TRUE  TRUE
all(v > 6)
#> [1] FALSE    # not all elements match this condition
any(v > 6)
#> [1] TRUE     # at least one element matches

আরও জটিল লজিক্যাল এক্সপ্রেশনে & আর | অপারেটর ব্যবহার করা জরুরি, কারণ এগুলো ভেক্টরে কাজ করে। দুটি অক্ষরের && আর || কেবল একটি একটি মান তুলনা করার জন্য, যেমনটি [বুলিয়ান কনসেপ্ট][concept-boolean]-এ আলোচনা করা হয়েছে।

v <- c(4, 7, 10)
v %% 2 == 0 & v > 5
#> [1] FALSE FALSE  TRUE

R-এ ভেক্টর সর্বত্র

পরের টপিকগুলোতে এ নিয়ে আবার আলোচনা হবে। আপাতত কনসোলে আউটপুটের ফরম্যাটটি খেয়াল করুন:

1:20
#> [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17
#> [18] 18 19 20

লাইনগুলো [ ]-এর ভেতরে সংখ্যা দিয়ে শুরু হয়, যা প্রথম এলিমেন্টের ইনডেক্স বোঝায় (লম্বা ভেক্টর একাধিক লাইনে গড়িয়ে গেলে এটি কাজে লাগে)। কিন্তু একটিমাত্র মানের আগে [1] থাকে কেন?

Note

R-এ প্রকৃত স্কেলার মান বলতে কিছু নেই!

একটি একক সংখ্যা বা অক্ষর যা মনে হয়, তা আসলে দৈর্ঘ্য ১-এর একটি ভেক্টর।

নিউমেরিক ও লজিক্যাল টাইপ নিয়ে বেসিকস ও বুলিয়ান কনসেপ্টে এর আভাস আগেই পাওয়া গেছে।

নোটেশন নিয়ে দুটি কথা

উপরে বর্ণিত ভেক্টরগুলোকে আরও আনুষ্ঠানিকভাবে atomic vectors বলা হয়। কারণ এগুলো শুধু সরল, অবিভাজ্য (তাই "atomic") মান ধারণ করতে পারে, যেমন numeric, character, boolean। আরও জটিল গঠন recursive vectors তৈরি করতে পারে, যেগুলোর সাথে পরিচয় হবে lists নিয়ে আলোচনা করার সময়।

GitHub-এর মাধ্যমে সম্পাদনা করুন লিংকটি নতুন একটি উইন্ডো বা ট্যাবে খুলবে

ভেক্টর শিখুন