ট্র্যাক
/
R
R
/
সিলেবাস
/
ম্যাট্রিক্স ও অ্যারে
ম্

ম্যাট্রিক্স ও অ্যারে মধ্যে R

{one: "১টি অনুশীলনী", other: "%{count}টি অনুশীলনী"}

ম্যাট্রিক্স ও অ্যারে সম্পর্কে

সমজাতীয় অ্যাটমিক ডেটার সংগ্রহ নিয়ে কাজ করার সময় (যেমন সবগুলো সংখ্যা বা সবগুলো ক্যারেক্টার), R-এ নিচের স্ট্রাকচারগুলো ব্যবহার করা যায়:

  • এক-মাত্রিক ডেটার জন্য vector, যা একটি ইনডেক্স দিয়ে অ্যাক্সেস করা হয়।
  • দুই-মাত্রিক, আয়তাকার (র্যাগড নয়) ডেটার জন্য matrix.
  • সাধারণ N-মাত্রিক ক্ষেত্রে array. একটি matrix আসলে N=2 সহ একটি array মাত্র।
Note

Python প্রোগ্রামারদের জন্য: এই অংশটি চেনা চেনা লাগতে পারে।

NumPy-এর সাথে যে মিল আছে, সেটি আকস্মিক নয় (তবে R একটু আগের, আর এই সবকিছু এর বেস ভাষাতেই আছে)।

ম্যাট্রিক্স

একটি ম্যাট্রিক্স আসলে একটি ভেক্টরই, সাথে আকৃতি নির্ধারণের জন্য সারি ও কলামের সংখ্যা।

এগুলো তৈরি করার জন্য একটি matrix() ফাংশন আছে:

# data already available 
matrix(1:6, nrow=2, ncol=3)
#>      [,1] [,2] [,3]
#> [1,]    1    3    5
#> [2,]    2    4    6

# empty matrix to be filled in later
matrix(nrow=2, ncol=3)
#>      [,1] [,2] [,3]
#> [1,]   NA   NA   NA
#> [2,]   NA   NA   NA

খেয়াল করুন, ডেটা কলাম-মেজর অর্ডারে সংরক্ষিত থাকে (অর্থাৎ আগে নিচে, তারপর পাশে)। এটি Fortran, Matlab ও Julia-র মতোই, কিন্তু C/C++ ও NumPy থেকে আলাদা।

সারি ও কলাম দুটোর জন্যই ম্যাট্রিক্সের ডাইমেনশন জানতে dim(), আর একটি মাত্র ডাইমেনশন পেতে nrow() বা ncol() ব্যবহার করুন। length() ব্যবহার করলে কেবল অন্তর্নিহিত ভেক্টরের দৈর্ঘ্যই ফেরত আসবে: মোট এলিমেন্টের সংখ্যা (উপরের উদাহরণে 6)।

আরও কিছু ফাংশন ম্যাট্রিক্স আউটপুট তৈরি করে, যেমন str_split_fixed().

library(stringr)

str_split_fixed(c("split some words", "and some more"), " ", 3)
#>      [,1]    [,2]   [,3]   
#> [1,] "split" "some" "words"
#> [2,] "and"   "some" "more" 

ম্যাট্রিক্স ইনডেক্সিং

এটি ভেক্টর ইনডেক্সিংয়ের সব উপায়েই কাজ করে, শুধু সারি ও কলাম যথাক্রমে উল্লেখ করতে হয়। পুরো সারি বা কলাম পেতে একটি ডাইমেনশন খালি রাখুন।

উপরের একই ম্যাট্রিক্স ব্যবহার করে:

m <- matrix(1:6, nrow=2, ncol=3)
m
#>      [,1] [,2] [,3]
#> [1,]    1    3    5
#> [2,]    2    4    6

m[2, 3]    # row 2, col 3
#> [1] 6

m[1:2, 3]  # rows 1:2, col 3
#> [1] 5 6

 m[2, ]    # all of row 2
#> [1] 2 4 6

খেয়াল করুন, একটিমাত্র সারি বা কলামের সাবসেট ভেক্টর হিসেবে ফেরত আসবে, ম্যাট্রিক্স হিসেবে নয়।

class(m)
#> [1] "matrix" "array" 
class(m[2,])
#> [1] "integer"

এই ধরনের dimension reduction সব সময় কাঙ্ক্ষিত নয়, বিশেষ করে এমন ফাংশন পাইপলাইনে যা ম্যাট্রিক্স ইনপুট প্রত্যাশা করে।

drop=FALSE উল্লেখ করলে ম্যাট্রিক্স ইনপুট থেকে ম্যাট্রিক্স রিটার্ন ভ্যালু নিশ্চিত হবে। খেয়াল করুন, কেবল একটি সারি বা একটি কলামবিশিষ্ট ম্যাট্রিক্স আর ভেক্টর একই টাইপ নয়।

m[2, , drop = FALSE]
#>      [,1] [,2] [,3]
#> [1,]    2    4    6

as.matrix() ফাংশন একটি ভেক্টরকে এক-কলামের ম্যাট্রিক্সে রূপান্তর করে।

as.matrix(1:3)
#>      [,1]
#> [1,]    1
#> [2,]    2
#> [3,]    3

ভেক্টরের মতোই, নতুন মান অ্যাসাইন করে ম্যাট্রিক্সের অংশবিশেষ পরিবর্তন করা যায়।

m[, 2] <- c(10, 20)
m
#>      [,1] [,2] [,3]
#> [1,]    1   10    5
#> [2,]    2   20    6

সারি/কলাম যোগ ও মুছে ফেলা

ভেক্টরের ক্ষেত্রে ডেটা ঢোকাতে ও যোগ করতে c() ফাংশনই যথেষ্ট ছিল। ম্যাট্রিক্সের গঠন বেশি, তাই কী দরকার তা নির্দিষ্ট করতে বেশি যত্ন লাগে।

rbind() ও cbind() ফাংশন ম্যাট্রিক্সের সাথে নতুন সারি বা কলাম যুক্ত করে।

m
#>      [,1] [,2] [,3]
#> [1,]    1    3    5
#> [2,]    2    4    6
m2 <- matrix(7:9, nrow = 1, ncol = 3)

rbind(m, m2)
#>      [,1] [,2] [,3]
#> [1,]    1    3    5
#> [2,]    2    4    6
#> [3,]    7    8    9

ভেক্টরের মতোই, সারি বা কলাম মুছতে ঋণাত্মক ইনডেক্সিং ব্যবহার করা হয়।

m
#>      [,1] [,2] [,3]
#> [1,]    1    3    5
#> [2,]    2    4    6

m[, -2]
     #> [,1] [,2]
#> [1,]    1    5
#> [2,]    2    6

ফিল্টারিং ও ফাংশন

সব ভেক্টর ফাংশনই ম্যাট্রিক্সে কাজ করে, সব এলিমেন্টের উপর প্রয়োগ হয়ে। তবে তারা ম্যাট্রিক্সের গঠন হারিয়ে ভেক্টর ফেরত দিতে পারে।

sqrt(m)
#>          [,1]     [,2]     [,3]
#> [1,] 1.000000 1.732051 2.236068
#> [2,] 1.414214 2.000000 2.449490

sum(m)
#> [1] 21

m[m > 3]
#> [1] 4 5 6

ম্যাট্রিক্সের জন্য colSums() ও rowSums() ফাংশনও কাজে লাগতে পারে। এখানে ডাইমেনশন রিডাকশনই কাঙ্ক্ষিত, তাই রিটার্ন ভ্যালুগুলো ভেক্টর।

# m as defined above
rowSums(m)
#> [1]  9 12
colSums(m)
#> [1]  3  7 11

একইভাবে, গড় নির্ণয়ের জন্য rowMeans() ও colMeans() ফাংশন আছে।

ম্যাট্রিক্সে কাজ করা সাধারণ ফাংশন

অন্য কনসেপ্টে আমরা দেখেছি, Tidyverse লাইব্রেরিগুলো ভেক্টর ও অ্যারে (purrr) বা ডেটাফ্রেম (dplyr) নিয়ে কাজ সহজ করতে পারে।

তবে ম্যাট্রিক্স ও অ্যারে বেশিরভাগ ক্ষেত্রেই Tidyverse ইনপুটের আওতার বাইরে (অন্তত এখন তো বটেই)।

apply() ফাংশন Base R-এর অংশ, আর ম্যাট্রিক্স প্রোগ্রামিংয়ের সূক্ষ্ম নিয়ন্ত্রণের জন্য এখনও সেরা হাতিয়ার।

প্যারামিটারগুলো ক্রমানুসারে:

  1. ইনপুট ম্যাট্রিক্স।
  2. যে ডাইমেনশনে কাজ করতে হবে (সারির জন্য 1, কলামের জন্য 2)।
  3. যে ফাংশনটি প্রয়োগ করতে হবে।
  4. ঐচ্ছিকভাবে, ফাংশনের জন্য যেকোনো অতিরিক্ত প্যারামিটার।

rowMeans() ফাংশন Base R-এ আছে, তবে apply() ও mean() দিয়েও এটি নকল করা যায়।

randm <- sample(1:10, 16, replace = TRUE) |> matrix(4, 4)
randm
#>      [,1] [,2] [,3] [,4]
#> [1,]    4    9    8    3
#> [2,]    6    8    5    5
#> [3,]    4    2    1    2
#> [4,]    4    2    5    4

apply(randm, 1, mean)
#> [1] 6.00 6.00 2.25 3.75

rowMeans(randm)
#> [1] 6.00 6.00 2.25 3.75

লিনিয়ার অ্যালজেবরা

Note

এই অংশটি একধরনের গাণিতিক জ্ঞান ধরে নেয়, যা Exercism-এর পরিধির বাইরে।

এটি আপনার কাছে দুর্বোধ্য লাগলে অনুগ্রহ করে এড়িয়ে যান।

তবে R একটি ডেটা সায়েন্স ভাষা, আর অনেক ব্যবহারকেরই ফলিত গণিত ও স্ট্যাটিস্টিকসের পটভূমি আছে। এই সংক্ষিপ্ত সারসংক্ষেপ কিছু শিক্ষার্থীর কাজে লাগতে পারে।

আধুনিক R "স্পষ্টতই" একটি ডেটা সায়েন্স ভাষা: মূলত টেবুলার ডেটা নিয়ে কাজ করার জন্য তৈরি, আর স্ট্যাটিস্টিশিয়ান, এপিডেমিওলজিস্ট ও সমাজবিজ্ঞানীদের মতো ব্যবহারকারীদের মধ্যে জনপ্রিয়। এই ক্ষেত্রে এর প্রধান প্রতিদ্বন্দ্বী Python-এর সায়েন্টিফিক স্ট্যাক, যার মধ্যে Pandas বা Polars-এর মতো প্যাকেজ আছে।

তবে আগের দশকগুলোতে R-কে একটি সম্ভাব্য ইঞ্জিনিয়ারিং ভাষা হিসেবেও দেখা হতো, যা সরাসরি Matlab-এর সাথে প্রতিদ্বন্দ্বিতা করত।

আশ্চর্যজনকভাবে, Base R এখনও ভেক্টর ও ম্যাট্রিক্সে লিনিয়ার অ্যালজেবরার সম্পূর্ণ পরিসরের অপারেশন সমর্থন করে। এগুলো এখন ব্যবহারকারীর কোডে কতটা ব্যবহৃত হয় তা স্পষ্ট নয়, তবে স্ট্যাটিস্টিক্যাল ফাংশন বাস্তবায়নের জন্য এসব কৌশল ভেতরে খুবই গুরুত্বপূর্ণ থেকে যায়।

R-এ LinAlg এখনও কিছু কলেজ কোর্সে শেখানো হয়, যেমন এই ইকোনোমেট্রিক্স ক্লাসে. গণিতের (প্রোগ্রামিং নয়) একটি ভালো নির্দেশিকা আছে 3Blue1Brown-এ।

Advanced

Exercism-এর মধ্যে লিনিয়ার অ্যালজেবরার সবচেয়ে পূর্ণাঙ্গ আলোচনা রয়েছে Julia সিলেবাসে (R সিলেবাসের লেখকদেরই লেখা)। আমাদের বিশ্বাস, গুরুতর লিনিয়ার অ্যালজেবরার কাজে R-এর চেয়ে Julia (বা যেখানে numpy.linalg মডিউল পাওয়া যায় সেখানে Python) এখন বেশি উপযুক্ত ভাষা হবে।

ডায়াগোনাল

একটি বর্গ (N x N)) ম্যাট্রিক্স A-এর প্রধান ডায়াগোনাল উপরের বাম (A[1,1]) থেকে নিচের ডানে (A[N,N]) পর্যন্ত বিস্তৃত।

diag() ফাংশনটি তার কাছে পাঠানো আর্গুমেন্টের উপর নির্ভর করে ভিন্নভাবে আচরণ করে।

একটি ভেক্টর v দিলে diag(v) একটি ডায়াগোনাল ম্যাট্রিক্স তৈরি করে।

diag(1:3)
#>      [,1] [,2] [,3]
#> [1,]    1    0    0
#> [2,]    0    2    0
#> [3,]    0    0    3

একটি বর্গ ম্যাট্রিক্স A দিলে diag(A) প্রধান ডায়াগোনালের এলিমেন্টগুলো একটি ভেক্টর হিসেবে ফেরত দেয়।

A
#>      [,1] [,2] [,3]
#> [1,]   10    5    2
#> [2,]    9    3    7
#> [3,]    8   10    4
diag(A)
#> [1] 10  3  4

একটি মাত্র ইন্টিজার k দিলে diag(k) একটি k × k আইডেন্টিটি ম্যাট্রিক্স তৈরি করে: সম্ভবত আপনি যা অনুমান করেছিলেন তা নয়।

এমনকি গুরুতর R পাঠ্যবইও এখানে "ভাবুন তো"-এর মতো মন্তব্য যোগ করে।

diag(3)
#>      [,1] [,2] [,3]
#> [1,]    1    0    0
#> [2,]    0    1    0
#> [3,]    0    0    1

ট্রান্সপোজ ও ইনভার্স

সারি ও কলাম বদলাতে t() ফাংশন যেকোনো ম্যাট্রিক্স ট্রান্সপোজ করে।

m
#>      [,1] [,2] [,3]
#> [1,]    1    3    5
#> [2,]    2    4    6
t(m)
#>      [,1] [,2]
#> [1,]    1    2
#> [2,]    3    4
#> [3,]    5    6

জটিল-মানের ম্যাট্রিক্সের ক্ষেত্রে ফলাফল জটিল কনজুগেট নয়। ম্যাট্রিক্স A-এর কনজুগেট ট্রান্সপোজ (অ্যাডজয়েন্ট) পেতে Conj(t(A)) ব্যবহার করুন।

উচ্চতর মাত্রার অ্যারের জন্য aperm() ডাইমেনশন পারমিউট করে।

বর্গ ম্যাট্রিক্স A-এর ইনভার্সের জন্য আমরা solve(A) ব্যবহার করতে পারি। আমাদের অনেকের কাছেই এই সিনট্যাক্স ... অপ্রত্যাশিত লাগে।

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

A <- matrix(sample(1:10, 9, replace = TRUE), 3, 3)
A
#>      [,1] [,2] [,3]
#> [1,]   10    5    2
#> [2,]    9    3    7
#> [3,]    8   10    4

solve(A)
#>             [,1]        [,2]        [,3]
#> [1,]  0.16666667  0.00000000 -0.08333333
#> [2,] -0.05747126 -0.06896552  0.14942529
#> [3,] -0.18965517  0.17241379  0.04310345

A %*% solve(A) |> round(digits = 10)
     [,1] [,2] [,3]
#> [1,]    1    0    0
#> [2,]    0    1    0
#> [3,]    0    0    1

গুণ

+, -, *, ^-এর মতো সাধারণ গাণিতিক অপারেটরগুলো ম্যাট্রিক্সে এলিমেন্ট-ভিত্তিক কাজ করে। ডাইমেনশন না মিললে রিসাইক্লিংয়ের স্বাভাবিক নিয়মগুলো প্রযোজ্য হয়।

m
#>      [,1] [,2] [,3]
#> [1,]    1    3    5
#> [2,]    2    4    6

m * m
#>      [,1] [,2] [,3]
#> [1,]    1    9   25
#> [2,]    4   16   36

# same calculation, different syntax
m ^ 2
#>      [,1] [,2] [,3]
#> [1,]    1    9   25
#> [2,]    4   16   36

ভেক্টর ও ম্যাট্রিক্স গুণের অন্যান্য বিভিন্ন ধরন ব্যাখ্যা করা আমাদের পরিধির বাইরে, তবে খুব সংক্ষেপে:

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