6. ভেক্টর (Vector)

আমি যদি তোমাকে প্রশ্ন করি, ভেক্টর কি? তুমি নিশ্চয় চটজলদি উত্তর দিয়ে দেবে "যে রাশির মান ও দিক আছে তাকেই ভেক্টর বলে।" উত্তর ঠিকই আছে, কিন্তু আমরা আজকে যে ভেক্টর নিয়ে কথা বলবো এই ভেক্টর সেই ভেক্টর নয় রে পাগলা! 😂 আমরা আজকে কথা বলবো R প্রোগ্রামিং ভাষায় ভেক্টর বলতে কি বুঝানো হয়। এবং এর নাড়িভূড়ি সমন্ধে জানার চেষ্টা করবো।

মূলত R প্রোগ্রামিং ভাষার বিশাল একটা অংশ জুড়ে এই ভেক্টরের পরিধি। বেশিরভাগ ক্ষেত্রেই দেখা মিলবে ভেক্টরের। আমরা জানি ভেরিয়েবলে একটি ডেটা বা একটি ভ্যালু স্টোর করে রাখা যায়। কিন্তু সবসময় কি তাই যথেষ্ট? অনেকসময় আমাদের অনেকগুলো ডেটা নিয়ে কাজ করতে হয়, তখন কি আমরা অনেকগুলো ভেরিয়েবল বানাবো? যেমন ধরো, তোমাকে তোমার ক্লাসের সবার ইনকোর্সের মার্ক নিয়ে কাজ করতে হবে। তখন তুমি কি করবে? mark1, mark2, mark3....... এভাবে লিখতে থাকবে? যদি তোমার ক্লাসে ২০/২৫ জন থাকে তাহলে হয়তো লিখে ফেলা যেতে পারে। কিন্তু তোমার ক্লাসে যদি ৫০০ জন স্টুডেন্ট থাকে তাহলে কি তুমি এভাবে বসে বসে mark500 পর্যন্ত ভেরিয়েবল লিখবে? নিশ্চয় না, কারণ তুমি বুদ্ধিমান ছেলে। তুমি নিশ্চয় বোকার মতো এইকাজ করতে যাবেনা। তুমি নিশ্চয় অন্যকোনো উপায় খুজছো মনেমনে। আমি এখন সেই উপায়টিই বলবো। সেটি হচ্ছে ভেক্টর। সহজ বাংলায় ভেক্টর বলতে বুঝায়, একটি ভেরিয়েবল দিয়ে অনেক ভেরিয়েবলের কাজ চালিয়ে দেয়া। মানে একটি ভেরিয়েবলেই অনেক ভ্যালু বা ডেটা স্টোর করা যাবে। এবং সেগুলোকে আলাদাভাবে স্বাধীন ভ্যারিয়েবল এর মতো ব্যাবহারও করা যাবে! চমৎকার না!? ফাও প্যাচালের দরকার নাই, সরাসরি উদাহরণে চলে যাচ্ছি,

> x<- c(12, 18, 23, 24, 21)
> x
[1] 12 18 23 24 21

এখানে আমি x নামের একটা ভ্যারিয়েবল এ অনেকগুলো ভ্যালু একসাথে ইনপুট দিয়ে দিয়েছি। কিন্তু এই কাজটা করেছি c() ফাংশন ব্যাবহার করে। c for combine. মানে সবগুলো ভ্যালুকে একসাথে কম্বাইন্ড করে এই ভ্যারিয়েবলে রেখে দিয়েছি। তারপর x লিখে এন্টার প্রেস করেছি, সবগুলো ভ্যালু আউটপুট আকারে দেখা যাচ্ছে। চমৎকার! তাহলে আমাদের মনে রাখতে হবে যে, c() ফাংশনের ভেতর কমা দিয়ে আলাদা করে যতগুলো ভ্যালু দেওয়া হবে সবগুলো মিলে একটা ভেক্টর তৈরি হবে।

নিজে করিঃ 23, 25, 37, 19, 54 এই পাচটি মান নিয়ে y নামের একটা ভেক্টর তৈরী করতে হবে।

এবারে আরেকটা জিনিস ক্লিয়ার করতে চাই। নিচের উদাহরণটি দেখোঃ

> x<- c(12, 25, 48, 78, 65, 78, 12, 45, 35, 94, 85, 85, 12, 25, 48, 78, 65, 78, 12, 45, 35, 94, 85, 85, 91)
> x
[1] 12 25 48 78 65 78 12 45 35 94 85 85 12 25 48 78 65 78 12 45 35 94 85
[24] 85 91

২৫ টি ভ্যালু নিয়ে একটি ভেক্টর বানিয়েছি। এবং তাদের আউটপুট দেখার চেষ্টা করেছি। কিন্তু আমি যেটা দেখাতে চাচ্ছি সেটা হলো, তোমরা লক্ষ্য করো এই আউটপুটের সামনে [1] এবং [24] এরকম আছে। এর কারন কি? আমি বলেছিলাম পরে এর ব্যাখা দেবো। ব্যখ্যাটা হচ্ছে, R এ যখন আমরা কোনো কাজ করি এবং তার আউটপুট নেয়ার চেষ্টা করি, তখন কম্পিউটার আমাদেরকে সেই আউটপুউট গুলো ভেক্টর হিসেবে দেখানোর চেষ্টা করে। এবং [1], [24] এই সংখ্যাগুলো হলো আমাদের আউটপুট ভ্যালুর পজিশন। পজিশন বলতে ভ্যালুটি কততম স্থানে আছে তা বোঝাচ্ছে। যেমন প্রথমেই আছে [1] এটি দ্বারা বোঝাচ্ছে 12 ভ্যালুটি প্রথমেই আছে। 85 ভ্যালুটি আছে 24th পজিশনে। সেজন্যে তার সামনে [24]

> 2+3
[1] 5

এখন নিশ্চয় বুঝতে পেরেছো প্রতিটি আউটপুটের সামনে কেন [1] থাকে? কারন সব আউটপুটই আসে ভেক্টর হিসেবে। এবং একটা মাত্র ভ্যালু থাকার ফলে তার পজিশন হয় প্রথম। সেজন্যেই সামনে একটা [1] থাকে। আশাকরি উত্তরটা পেয়েছো। এবং বুঝতেও পেরেছো! না বুঝলে অবশ্যই তোমরা আমাকে বলবে। কারন এই বিষয়টি তুমি কোথাও সহজে খুজে পাবেনা।

আবারও শুরুর ভেক্টরটি দিয়েই কাজ করা যাক,

> x<- c(12, 18, 23, 24, 21)
> x
[1] 12 18 23 24 21

আমরা বলেছিলাম ভেক্টরের প্রতিটি ভ্যালুকে আলাদাভাবে ইউজ করা যায়। কিন্তু সেটি কিভাবে? মনে করো তুমি এই x ভেক্টরের চতুর্থ ভ্যালু 24 কে নিয়ে কাজ করতে চাও। তাহলে একে আলাদা করবে কিভাবে?কিভাবে? তুমি কি একটু চিন্তা করে বলতে পারবে? না পারলে নিচে আমার কোড দেখো, কিন্তু তার আগে অবশ্যই নিজেরা চিন্তা করার অভ্যাসটি করবে অবশ্যই।

> x[4]
[1] 24

আমি যদি ভ্যারিয়েবলের নামের সাথে তৃতীয় বন্ধনীর মধ্যে কোনো ভ্যালুর পজিশন বলে দেই তাহলে সেই ভ্যালুটি আউটপুট হিসেবে আসে। যেমন এখানে x[4] লিখার ফলে চতুর্থ ভ্যালুটি এসেছে। এই বন্ধনীর ভিতরে এভাবে ভ্যালু বের করাকে বলা হয় ইনডেক্সিং। তুমি কি একবার x[6], x[7], x[8] লিখে চেষ্টা করে দেখবে কি হয়?

> x[7]
[1] NA

আউটপুট এসেছে NA যার অর্থ হলো Not Available এখানে মোট ভ্যালুই আছে মাত্র পাচটি, তাহলে সপ্তম পজিশনে ভ্যালু কোত্থেকে আসবে? কাজেই আমরা যদি অবান্তর কোনো পজিশনের ভ্যালু পাবার চেষ্টা করি তাহলে কোনো লাভ হবেনা। আশাকরি একটা ভেক্টর থেকে কিভাবে একটা ভ্যালু আলাদা করতে হয় সেটা শিখেছো। এবারে আমরা একাধিক ভ্যালু আলাদা করার চেষ্টা করবো। যেমন আমি যদি দ্বিতীয় আর চতুর্থ ভ্যালুটি আলাদা করতে চাই তাহলে কি করতে হবে?

> x[c(2,4)]
[1] 18 24

আমরা এখানে ইনডেক্স হিসেবে একটা ভেক্টর দিয়েছি। c(2, 4) যেই যেই পজিশনগুলোর ভ্যালু চাই সেগুলো নিয়ে ভেক্টর বানিয়ে দিতে হবে। আরেকটা উদাহরণ দেখোঃ

> x<- c(12, 25, 48, 78, 65, 78, 12, 45, 35, 94, 85, 85, 12, 25, 48, 78, 65, 78, 12, 45, 35, 94, 85, 85, 91)
> x
[1] 12 25 48 78 65 78 12 45 35 94 85 85 12 25 48 78 65 78 12 45 35 94 85
[24] 85 91
> x[c(13, 21, 6)]
[1] 12 35 78

আবারও আমরা সেই ২৫ টি ভ্যালু নিয়ে একটা ভেক্টর বানালাম, এবং তার আউটপুট বের করলাম। আমরা এই ভেক্টরটি থেকে 13, 21 এবং 6 পজিশনে থাকা ভ্যালুগুলো দেখার চেষ্টা করেছি। কিভাবে একাধিক ভ্যালু আলাদা করতে হয় নিশ্চয় বুঝেছো। এবারে ভেক্টর বানানোর অন্য একটা পদ্ধতি দেখবো।

> y<- 12:17
> y
[1] 12 13 14 15 16 17

12:17 লেখার ফলে একটা ভেক্টর তৈরী হলো। যার ভ্যালুগুলো হলো ১২ থেকে ১৭। চমৎকার না? আমরা যদি ক্রমিক সংখ্যা নিয়ে ভেক্টর বানাতে চাই তাহলে এই টেকনিক অ্যাপ্লাই করতে পারি। যেমনঃ 1:100 লিখলে আমরা থেকে ১০০ পর্যন্ত ভ্যালু পাবো। এটা তেমন জটিল কিছুনা, নিজেরাই কোড রান দিয়ে দেখে নিতে । আশাকরি বুঝতে পেরেছো। এবারে তুমি যদি লিখো 9:1 তাহলে আউটপুট কিরকম আসা উচিৎ বলে তোমার মনেহয়? নিচের উদাহরণ দেখোতো, তুমি কি এরকম কিছু ভেবেছো? তাহলে তোমাকে অভিনন্দন! তুমি বুঝতে পেরেছো!

> 9:1
[1] 9 8 7 6 5 4 3 2 1

এর মানে হলো, আমরা যদি এভাবে উল্টো করে লিখি তাহলে উল্টো সিকোয়েন্স পাওয়া যাবে। এখানে না বুঝার কিছু নাই। এবারে আমরা এরকম সিকোয়েন্স তৈরি করার অন্য একটা পদ্ধতি দেখবো। মনেকরো তুমি শুধু জোড় সংখ্যাগুলো বা বিজোড় সংখ্যাগুলো দেখতে চাচ্ছো। তাহলে কি করতে হবে? ওয়েল! তোমরা নিচের উদাহরনটা দেখলেই বুঝতে পারবে।

> seq(1, 20, 2)
[1] 1 3 5 7 9 11 13 15 17 19
> seq(2, 20, 2)
[1] 2 4 6 8 10 12 14 16 18 20

seq() ফাংশনের সাহাযে আমরা এরকম ইচ্ছামত নাম্বার সিকোয়েন্স তৈরি করতে পারি। এই ফাংশনের প্রথম আর্গুমেন্ট হচ্ছে সিকোয়েন্স এর শুরু (আর্গুমেন্ট কি জিনিস, তার বিস্তারিত উত্তর পাবে "ফাংশন" অধ্যায়ে) দ্বিতীয় আর্গুমেন্ট টা হচ্ছে সিকোয়েন্স এর শেষ। এবং তৃতীয় আর্গুমেন্ট টা হলো ইনক্রিমেন্ট। মানে আমাদের সংখ্যা ধারায় কত করে বৃদ্ধি পাবে সেই পরিমানটা বলে দিতে হবে। তোমরা নিজেরা seq(2, 20, 3) লিখে এন্টার প্রেস করে দেখো। তাহলে আর কোন সংশয় থাকবেনা। যদি উল্টো করে লিখি, তাহলে আগের মতই উল্টো সিকোয়েন্স আসবে।

> seq(20, 2, -2)
[1] 20 18 16 14 12 10 8 6 4 2

তোমরা এই seq() ফাংশন ব্যাবহার করে নিজেদের ইচ্ছামত পাচ দশঘর পরিমাণ কমিয়ে অথবা বাড়িয়ে প্রয়োজনমত নাম্বার সিকোয়েন্স বানাতে পারবে। যেমনঃ seq(15, 200, 13) লিখে এন্টার প্রেস করে দেখো।

তুমি যদি কোনো ভেক্টরে কতটি উপাদান আছে তা দেখতে চাও তাহলে length() ফাংশনটি ব্যাবহার করতে পারো।

> length(x)
[1] 5

এবং তুমি যদি ভেক্টর থেকে কোনো উপাদান বাদ দিয়ে দিতে চাও, তাও করতে পারবে। তারজন্য নেগেটিভ ইনডেক্সিং করতে হবে। ব্যাপারটি উদাহরণে বোঝাচ্ছি, মনেকরো তুমি x ভেক্টর থেকে চতুর্থ উপাদানটি বাদ দিতে চাও। তাহলে,

> x
[1] 12 18 23 24 21
> x[-4]
[1] 12 18 23 21

দেখো, x[-4] লিখার ফলে চতুর্থ উপাদানটি বাদ পড়ে গেছে। একেই বলা হয় নেগেটিভ ইনডেক্সিং। অনেক মজা না?

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

> rep(x, 3)
[1] 12 18 23 24 21 12 18 23 24 21 12 18 23 24 21

এখানে দেখো rep(x, 3) লিখার ফলে x ভেক্টরটি তিনবার পুনরাবৃত্তি ঘটেছে। এই ফাংশনটিকে আরো কয়েকরকম ভাবে ব্যাবহার করা যায়। আমি একে একে দেখাচ্ছি সেসব, তোমরা দেখলেই বুঝতে পারবে।

> rep(x, each=3)
[1] 12 12 12 18 18 18 23 23 23 24 24 24 21 21 21

এবারে আমি বলেই দিয়েছি each=3 এর মানে আমি প্রত্যেকটা ভ্যালুই তিনবার করে চাচ্ছি। আগেরবারও তাই ই ছিলো। কিন্তু দুইরকম ভাবে লেখার ফলে দুইরকম আউটপুট এসেছে তা তোমরা নিজের চোখেই দেখতে পাচ্ছো। যখন তোমাদের যেরকম দরকার পড়বে সেরকম ব্যাবহার করবে। এতক্ষন আমরা প্রত্যেকটা ভ্যালুকেই সমান সংখ্যকবার রিপিট করেছি। কিন্তু যদি আমাদের একেকটা ভ্যালুকে আলাদা আলাদা সংখ্যক রিপিট করাতে হয় তাহলে আমরা কি করবো?

> rep(x, c(1, 4, 2, 1, 3))
[1] 12 18 18 18 18 23 23 24 21 21 21

এবারে দেখো আমি দ্বিতীয় আর্গুমেন্ট এ সিংগেল ভ্যালুর বদলে পুরো একটা ভেক্টর দিয়েছি। কারন প্রত্যেকটা ভ্যালুকে আমরা আলাদা সংখ্যক রিপিট করবো। প্রথম ভ্যালুটা একবার, দ্বিতীয় ভ্যালুটা চারবার, তৃতীয় ভ্যালুটা দুইবার এবং পঞ্চম ভ্যালুটা তিনবার রিপিট করানোর জন্যে আমরা c(1, 4, 2, 1, 3) ভেক্টরটি ইনপুট হিসেবে দিয়েছি। আমাদের ভেক্টরের ভ্যালুগুলো যথাযথ ক্রম অনুসারে রিপিট হয়েছে। ভালো করে খেয়াল করলেই বুঝতে পারবে। আরেকটা উদাহরন দেখোঃ

> rep(x, 1:5)
[1] 12 18 18 23 23 23 24 24 24 24 21 21 21 21 21

এবারেও আমরা সেইম কাজটাই করেছি। প্রথম ভ্যালুটি একবার, দ্বিতীয় ভ্যালুটি দুইবার, তৃতীয় ভ্যালুটি তিনবার এভাবে রিপিট করিয়েছি। সেজন্যে রিপিটেশন আর্গুমেন্ট হিসেবে আমাদের এক থেকে পাচ পর্যন্ত সংখ্যাগুলো দরকার ছিলো। সেজন্যে 1:5 কে ইনপুট দিয়ে দিয়েছি। এই গেলো মোটামুটি রিপিটেশনের বৃত্তান্ত। এবারে অন্য একটা কাজ করা যাক।

> x
[1] 12 18 23 24 21
> which(x==23)
[1] 3

আমরা দেখতে পাচ্ছি which(x==23) লিখে রান করানোর ফলে আউটপুট আসলো 3. তোমরা কি খেয়াল করেছো যে, এই 23 ভ্যালুটি আমাদের ভেক্টরের তৃতীয় ভ্যালু? তারমানে দাড়ালো, আমরা which() ফাংশন ব্যাবহার করে এভাবে কোনো ভ্যালুর পজিশন জানতে পারি। কোনো একটা নির্দিষ্ট ভ্যালু কোথায় আছে তা খুজে নিতে পারি। সেজন্যে আমাদের which() ফাংশনে একটা লজিক্যাল ভ্যালু ইনপুট করতে হবে। আমরা যে কোনো একটা ভ্যালুর পজিশন জানতে চাচ্ছি সেটা লজিক্যাল হিসেবে উপস্থাপন করতে হবে। কি খুব কঠিন লাগছে? তাহলে দেখো, আমরা এখানে 23 ভ্যালুটির পজিশন জানতে চাচ্ছি। সেজন্যে লিখেছি x==23 কারন এটা একটা লজিক্যাল ভেক্টর।

> x==23
[1] FALSE FALSE TRUE FALSE FALSE

তোমরা কি আউটপুটটি দেখে কিছু বুঝতে পারছো? যখন এই কোডটি লিখেছি তখন কম্পিউটার প্রত্যেকটি ভ্যালুকেই তুলনা করেছে 23 এর সাথে। যে, তারা সমান কিনা? যে ভ্যালুটি 23 এর সমান ছিলো শুধুমাত্র তার আউটপুট এসেছে TRUE বাকিগুলো সব ফলস। আমাদের which() ফাংশন এই ট্রু ফলস বুলিয়ান ভ্যালুগুলোকে ট্র্যাক করতে পারে, এবং আউটপুটে শুধু ট্রু ভ্যালুগুলোর অবস্থান জানায়। এভাবে আমরা কোনো একটা ভ্যালুর অবস্থান জানতে পারি। তোমরা which(x==21) লিখে এন্টার প্রেস করে দেখো আউটপুট কি আসে? এই চমৎকার ফাংশনটি ব্যাবহার করে শুধু একটা ভ্যালু না, অনেক ভ্যালুর পজিশন একসাথে জানা সম্ভব। আমরা কোনকোন ভ্যালুর পজিশন জানতে চাই সেই ব্যাপারটিকে শুধু লজিক্যালি উপস্থাপন করতে হবে। যেমনঃ আমরা যদি 20 এর চেয়ে ছোট ভ্যালুগুলোর অবস্থান জানতে চাই, তাহলে কোডটি হবে নিচের মত। কেননা, x<=20 লিখে যদি তুমি এন্টার প্রেস করো তাহলে একটা লজিক্যাল আউটপুট পাবে। নিজেরা একবার x<=20 লিখে রান করিয়ে দেখো।

> which(x<=20)
[1] 1 2

মানে হচ্ছে প্রথম ও দ্বিতীয় ভ্যালুটি ২০ এর চেয়ে ছোট। তাহলে তোমরা নিজেরা দেখোতো ২০ এরচেয়ে বড় ভ্যালুগুলো কিভাবে পাওয়া যেতে পারে? কাজটা নিজেরাই করার চেষ্টা করো।

কোনো ভেক্টরে কোনো একটা উপাদান আছে কিনা, বা উপাদানগুলো কোনো একটা সংখ্যা দ্বারা বিভাজ্য কিনা, বা ভেক্টরটিতে a থেকে b পর্যন্ত কোনো মান আছে কিনা (এখানে a, b যেকোনো সংখ্যা হতে পারে।) এরকম অনেক সিচুয়েশানের মুখোমুখি আমরা হতেই পারি! কোনো একটা ভেক্টর বা ডেটাসেট কোনো একটি শর্ত মেনে চলে কিনা তা যাচাই করা যেতে পারে any() ফাংশন দিয়ে। যেমন আমি যদি জানতে চাই আমাদের x ভেক্টর ছয় দ্বারা বিভাজ্য কিনা, এখানে ১৫ এর চেয়ে ছোট মান আছে কিনা অথবা ৫০ থেকে ৬০ এর মধ্যে কোনো মান আছে কিনা, তাহলে কোডগুলো হবে এরকম,

> any(x%%6)
[1] TRUE
> any(x<15)
[1] TRUE
> any(x>50 & x<60)
[1] FALSE

অর্থাৎ ছয় দ্বারা বিভাজ্য সংখ্যা আছে, ১৫ এর চেয়ে ছোট মানও আছে কিন্তু ৫০ থেকে ৬০ এর মধ্যে কোনো মান নেই। তোমরা কি বলতে পারবে, আমি এখানে একটা & অপারেটর কেন ব্যাবহার করেছি? যদি তোমরা লজিক্যাল ডেটা টাইপ এবং লজিক্যাল অপারেটর ভালোভাবে বুঝে থাকো তাহলে এটি বুঝতে পারার কথা। যদি না বুঝে থাকো তাহলে আবার দেখে নাও, আগেই বলেছিলাম এই ব্যাপারটা খুব গুরুত্বপূর্ন।

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

Hint: কোনো ভাগশেষ বের করার জন্যে %% অপারেটর ব্যাবহার করা হয়। একে বলা হয় মডিউলাস অপারেটর। কোনো সংখ্যা জোড় কিনা তা জানার জন্যে আমরা সেই সংখ্যাকে দুই দিয়ে ভাগ করে ভাগশেষ বের করি। যদি ভাগশেষ শুন্য হয় তাহলে সেইটি জোড় সংখ্যা। যদি ভাগশেষ এক হয়, তাহলে সেটি বিজোড় সংখ্যা। যেমনঃ 4%%2 লিখে এন্টারপ্রেস করলে আউটপুট আসবে শুন্য।

তাহলে x ভেক্টরকে দুই দিয়ে ভাগ করে ভাগশেষ বের করতে হবে এভাবে x%%2

এবারে which() ফাংশনে এটাকে ইনপুট করতে হবে। যেহেতু আমরা রেজাল্ট হিসেবে কিছু শুন্য আর এক পেয়েছি, সেহেতু আমরা এটাকে which() ফাংশনের ইনপুট হিসেবে ব্যাবহার করতে পাবোনা। কারণ, which() ফাংশনটি শুধুমাত্র লজিক্যাল ভ্যালু ইনপুট হিসেবে নিতে পারে। যেমন আমরা বের x<=20 এর আউটপুটে কিছু TRUE আর FALSE আসে। সেই জিনিসটাই আমাদের which() ফাংশনের ইনপুট হিসেবে কাজ করেছিলো। তাহলে এখন আমরা যদি x%%2 এর আউটপুট হিসেবে আসা শুন্য আর এক গুলোকে লজিক্যাল ভ্যালুতে কনভার্ট করতে চাই, আমাদের as.logical() ফাংশনটি ব্যাবহার করতে হবে (আগের অধ্যায়েই বলেছি কনভার্সনের ব্যাপারে)। এবং '!' (NOT operator) ও ব্যাবহার করতে হবে যথাযথ ভাবে। সেটি তোমরা নিজেরা মাথা খাটিয়ে বুঝে নেবে। এরপরও যদি না বুঝতে পারো, তাহলে আমি বলবো তোমার আরো মনোযোগ বাড়ানো উচিৎ। এরকম মনোযোগ নিয়ে প্রোগ্রামিং শিখতে পারবেনা। শিখতে চাইলে পুনরায় এর আগের অধ্যায়, এবং এই অধ্যায় পড়তে হবে। এটি নিজে নিজে না পারা পর্যন্ত নতুন কিছু পড়ার দরকার নেই।

problem: নিজেরা নিজেরা x+5, x-4, x*3, x/5 লিখে দেখো আউটপুট কি আসে? দেখে বোঝার চেষ্টা করো।

ছোটবেলায় আমরা সবাই "বড় থেকে ছোট সংখ্যাগুলি সাজিয়ে লেখো", "ছোট থেকে বড় সংখ্যাগুলি সাজিয়ে লেখো" এরকম সমস্যা সমাধান করেছি গণিত বইয়ে। বড় হবার পরও বিভিন্ন সময়ে আমাদের এই ছোট বড় সাজানোর কাজটি করতে হয়েছে বহুবার। আমাদের হাতে যদি কোনো ডেটাসেট থাকে এবং সেই ডেটাকে হয়ত উর্ধক্রম অথবা নিম্নক্রম অনুসারে সাজানোর দরকার হতেই পারে। এই কাজটি সুন্দরভাবে সম্পন্ন করার জন্যে R এ একটি ফাংশন রয়েছে। sort() ফাংশন। এটি ব্যাবহার করে ডেটাকে সাজানো যায়। যেমন ধরো, আমরা আমাদের x ভেক্টরকে উর্ধক্রম অনুসারে সাজাতে চাই। তাহলে,

> x
[1] 12 18 23 24 21
> sort(x)
[1] 12 18 21 23 24

যদি উল্টোদিকে অর্থাৎ নিম্নক্রম অনুসারে সাজাতে চাই তাহলে sort() ফাংশনে নতুন একটা আর্গুমেন্ট যোগ করতে হবে। তোমরা দেখলেই বুঝবে,

> sort(x, decreasing = TRUE)
[1] 24 23 21 18 12

decreasing=TRUE লিখার ফলে আমাদের ভ্যালুগুলো descending অর্ডারে সাজানো হয়ে গেলো। কি চমৎকার না?

অধ্যায় শেষ করবার আগে আরেকটা মজার জিনিস দেখাতে চাই। সেটা হচ্ছে তুমি চাইলে ভেক্টরে থাকা ভ্যালুগুলোর আলাদা আলাদা নামও দিতে পারো। তাদেরকে আলাদা করার সময় ইন্ডেক্স হিসেবে তাদের পজিশনের বদলে তুমি নাম ধরেও ভ্যালু আলাদা করে ফেলতে পারবে! যারা আমার মত ভ্যালুর পজিশন ভুলে যাও এটা তাদের জন্য অনেক আনন্দের সংবাদ হবে বলে আমি মনে করি।

> x
[1] 12 18 23 24 21

আমরা আমাদের x ভেক্টরের ভ্যালুগুলো দেখে নিলাম। এখন যদি আমি এই ভ্যালুগুলোর আলাদা আলাদা নাম দিতে চাই তাহলে names() ফাংশনটা ব্যাবহার করতে হবে।

> names(x) <- c("sakib", "tuhin", "suhas", "rakib", "tamim")
> x
sakib tuhin suhas rakib tamim
12 18 23 24 21

এখানে names(x) ব্যাবহার করে আমি ভ্যালুগুলোর নাম দিয়ে দিলাম। সবগুলো নাম একসাথে দেয়ার জন্যে ভেক্টর আকারে দিয়ে দিয়েছি c() ফাংশন ব্যাবহার করে। আর যেহেতু নামগুলো ক্যারেক্টার বা অক্ষরের সমন্বয়ে তৈরি সেজন্যে " " কোটেশন মার্ক ব্যাবহার করেছি। তুমি চাইলে সিঙ্গেল কোটেশনও ব্যাবহার করতে পারবে। ' ' এভাবে। কিন্তু কখনো " ' অথবা ' " এভাবে সিঙ্গেল কোট আর ডাবল কোট মিলিয়ে ফেলা যাবেনা। যাইহোক, নাম দেয়া শেষ করে তুমি যখন ভেক্টরটির ভ্যালুগুলো দেখার চেষ্টা করবে তখন দেখবে প্রত্যেকটা ভ্যালুর উপর তার নাম থাকবে। এখন তুমি চাইলে এই নামগুলো ধরেও ভ্যালু আলাদা করতে পারবে। যেমন, আমি যদি সুহাসের মার্ক আলাদা করতে চাই তাহলে,

> x["suhas"]
suhas
23

তৃতীয় বন্ধনীর ভিতরে পজিশনের বদলে সুহাসের নাম লিখলেও আমি ভ্যালুটি পেয়ে যাচ্ছি। ব্যাপারটা চমৎকার না? এর আগেও কিন্তু আমরা x[3] লিখে একই কাজটি করেছি। তুমি চাইলে শুধু নামগুলোও দেখতে পারো এভাবে,

> names(x)
[1] "sakib" "tuhin" "suhas" "rakib" "tamim"

এখানেও ইনডেক্সিং করা সম্ভব। যেমন চতুর্থ মার্কটি কার? তা যদি জানতে চাই তাহলে,

> names(x)[4]
[1] "rakib"

এখানে names(x) এর আউটপুট একটি ক্যারেকটার ভেক্টর, যেখানে আমাদের দেয়া নামগুলি আছে। এখন এই ভেক্টরের চার নাম্বার পজিশনে কোন নাম আছে তা জানার জন্যে আমরা names(x)[4] লিখেছি। এই হচ্ছে মোটামুটি নামকরণের পদ্ধতি। এর বাইরেও ভেক্টর সংক্রান্ত অনেক কিছুই আছে! লেখকও তো মানুষ! তার কি সব একসাথে মনে থাকা সম্ভব? তুমিই বলো! নতুন কিছু মনে পড়া মাত্রই উনি ইডিট করে দিবেন।

আপাতত এতটুকু জানলেই কাজ চালিয়ে নিতে পারবে। লুপ, ফাংশন ইত্যাদি আরো কিছু মৌলিক জিনিস শিখার পরে আমরা আরো বিভিন্ন রকম সর্টিং অ্যালগরিদমের সাথে পরিচিত হবো। এতদিনে যতটুকু শিখেছো সেটাই বারবার প্রাকটিস করবে। প্রোগ্রামিং শেখার সবচেয়ে বড় কৌশল হলো একটা জিনিস বারবার প্রাকটিস করতে করতে অভ্যাসে পরিণত করা, এবং নতুন সমস্যা নিয়ে এক্সপেরিমেন্ট করা। তোমরা যখন এই অভ্যাসগুলো আয়ত্ত করতে পারবে, তখন থেকেই একজন সত্যিকারের প্রোগ্রামার হওয়া শুরু হবে তোমার! 😊