NumPy Matrix Operation

عملیات ماتریسی

به گفته سایت معتبر towardsdatascience.com حدود 30 الی 40 درصد دانش مورد نیاز برای علوم داده و یادگیری ماشین مربوط به جبر خطی است و عملیات ماتریسی نقش بسیار مهمی در جبر خطی دارد.

در اینجا تعداد محدودی از مهمترین عملیات‌های ماتریسی را که در NumPy قابل اجرا هستند معرفی می‌کنیم.

تعریف ماتریس در NumPy

در نسخه‌های قدیمی‌تر NumPy یک کلاس مختص ماتریس‌ها وجود داشت و برای تعریف ماتریس از np.matrix() استفاده می‌شد، اما در نسخه‌های جدید از همان آرایه‌های معمول در NumPy که تا الان به معرفی آن‌ها پرداخته‌ایم برای تعریف ماتریس استفاده می‌شود.

برای مثال فرض کنید می‌خواهید یک ماتریس 3 در 3 بسازید.


import numpy as np
Array = np.array( [ [ 1, 2, 3 ],
                    [ 4, 5, 6 ],
                    [ 7, 8, 9 ] ] )
print(Array)

خروجی:

در کد زیر هم 3 ماتریس 6 در 6 ساخته‌ایم. اولی ماتریسی است که همه عناصر آن برابر یک، دومی ماتریسی که همه عناصر آن صفر و سومی یک ماتریس قطری است (ماتریسی که به جز عناصر قطر اصلی آن بقیه برابر صفر هستند).


import numpy as np

ones = np.ones([6,6])

zeros = np.zeros([6,6])

vector = np.array([1,2,3,4,5,6])
diagonal = np.diag(vector)

print('\n a 6 by 6 matrix (all elements equal to 1): \n', ones)
print('\n a 6 by 6 matrix (all elements equal to 0): \n', zeros)
print('\n a 6 by 6 diagonal matrix: \n', diagonal)


خروجی:

ضرب داخلی و ضرب خارجی

چنانکه می‌دانید ضرب داخلی دو بردار برابر یک عدد اسکالر است و ضرب خارجی دو بردار برداری دیگر است که بر هر دو بردار اولیه عمود می‌باشد.

جهت به دست آوردن ضرب داخلی دو بردار می‌توان از یکی از دو تابع inner() یا dot() استفاده کرد.


import numpy as np

# Vectors as 1D numpy arrays
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

print("a= ", a)
print("b= ", b)
print("\ninner:", np.inner(a, b))
print("dot:", np.dot(a, b))

خروجی:

برای به دست آوردن ضرب خارجی دو بردار می‌توان از تابع cross() استفاده کرد.


import numpy as np

# Vectors as 1D numpy arrays
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

print("a= ", a)
print("b= ", b)
print("dot:", np.cross(a, b))

خروجی:

ضرب ماتریسی

برای به دست آوردن حاصل ضرب دو ماتریس (در صورتی که ابعاد ماتریس‌ها جهت ضرب ماتریسی متناسب باشد)، می‌توان از یکی از دو روش آورده شده در کد زیر استفاده کرد.


import numpy as np

arr1 = np.array([[1, 2],
                 [3, 4]])
arr2 = np.array([[5, 6],
                 [7, 8]])

print('\nMatrix Product of arr1 and arr2 using np.matmul:\n', np.matmul(arr1, arr2))
print('\nMatrix Product of arr1 and arr2 using @ short form:\n', arr1 @ arr2)

خروجی:

به دست آوردن مقادیر بیشینه و کمینه در یک ماتریس

برای به دست آوردن مقادیر بیشینه و کمینه در یک ماتریس می‌توانید به ترتیب از توابع max() و min() استفاده کنید.

همچنین در صورتی که بخواهید شماره ایندکس محل رخداد بیشینه یا کمینه را به دست‌آورید به ترتیب می‌توانید از توابع argmax() و argmin() استفاده کنید.


import numpy as np

arr = np.array([[1, 25, 67],
                 [3, 45, -4],
                 [9, -18, 2]])

print(arr)

max_value = arr.max()
max_value_index = arr.argmax()

print(f'\n the maximum value in arr is: {max_value} which occurs at index {max_value_index}')

min_value = arr.min()
min_value_index = arr.argmin()

print(f'\n the minimum value in arr is: {min_value} which occurs at index {min_value_index}')

خروجی:

ترانسپوز یک ماتریس

چنانکه می‌دانید ترانسپوز یک ماتریس با عوض کردن جای سطرها و ستون‌های آن به دست می‌آید. در NumPy سه روش برای انجام این کار وجود دارد که در کد زیر می‌توانید آن‌ها را مشاهده کنید.


import numpy as np

a = np.array([[1, 2], [3, 4], [5, 6]])
print("a = ")
print(a)

print("\nWith np.transpose(a) function")
print(np.transpose(a))

print("\nWith ndarray.transpose() method")
print(a.transpose())

print("\nWith ndarray.T short form")
print(a.T)

خروجی:

برای یک بردار هم می‌توانید عمل ترانسپوز را انجام دهید. البته در NumPy یک مشکل تکنیکی وجود دارد که نمی‌توان عمل ترانسپوز را روی یک آرایه یک بعدی انجام داد. اگر می‌خواهید که ترانسپوز یک بردار را به دست آورید باید آرایه را به صورت دو بعدی به وسیله دو کروشه به شکل کد زیر مشخص کنید.


import numpy as np
a = np.array([[1, 2, 3]])

print("a = ")
print(a)

print("\na.T = ")
print(a.T)

خروجی:

توابع hstack ،stack و vstack

گاهی اوقات ممکن است بخواهیم که دنباله‌ای از آرایه‌ها را در محور دلخواه روی هم بچینیم. در این حالت از تابع stack() استفاده می‌کنیم. برای درک بهتر در شکل‌های زیر دو نحوه روی هم چیدن آرایه‌ها را نشان داده‌ایم.

تابع stack() آرایه‌ها را بر اساس محور تعیین شده برای آن، عنصر به عنصر به هم ملحق می‌کند. مقدار پیش فرض برای محور صفر در نظر گرفته شده است.


import numpy as np

arr1 = np.array([[1, 2, 3], [4, 5, 6]])
arr2 = np.array([[7, 8, 9], [10, 11, 12]])

stack_defualt = np.stack((arr1 ,arr2))
stack_axis0 = np.stack((arr1 ,arr2), axis = 0)
stack_axis1 = np.stack((arr1 ,arr2), axis = 1)


print('\n stack with default axis value\n', stack_defualt)
print('\n stack with axis = 0\n', stack_axis0)
print('\n stack with axis = 1\n', stack_axis1)

خروجی:

توابع hstack() و vstack() هم چنانکه از اسمشان پیداست به ترتیب ماتریس‌های داده شده به آن‌ها را به صورت افقی و عمودی در کنار هم می‌چینند. در حقیقت تابع اول ماتریس‌های داده شده به آن را به صورت سطر به سطر در کنار هم قرار می‌دهد (بسط ماتریس به صورت افقی) و تابع دوم ماتریس‌های داده شده به آن را زیر هم قرار می‌دهد (بسط ماتریس به صورت عمودی).


import numpy as np

arr1 = np.array([[1, 2, 3], [4, 5, 6]])
arr2 = np.array([[7, 8, 9], [10, 11, 12]])

hstack = np.hstack((arr1 ,arr2))
vstack = np.vstack((arr1 ,arr2))



print('\n horizontal stack of 2 arrays\n', hstack)
print('\n vertical stack of 2 arays\n', vstack)

خروجی:

به دست آوردن تریس یک ماتریس

تریس (trace) یک ماتریس مربعی، به مجموع عناصر قطری آن گفته می‌شود.


import numpy as np
a = np.array([[2, 2, 1],
               [1, 3, 1],
               [1, 2, 2]])
print("a = ")
print(a)
print("\nTrace:", a.trace())

خروجی:

به دست آوردن مرتبه یک ماتریس

مرتبه (rank) یک ماتریس، حداکثر تعداد بردارهای ستونی یا بردارهای سطری مستقل خطی آن ماتریس است.

مدول NumPy شامل تابع linalg مخفف linear algebra است که آن هم شامل بسیاری از مباحث و عملیات‌های جبر خطی می‌باشد و پیدا کردن مرتبه یا رنک یک ماتریس هم جزو آن‌ها است که در کد زیر آن را مشاهده می‌کنید.


import numpy as np
a = np.arange(1, 10)
a.shape = (3, 3)
print("a = ")
print(a)
rank = np.linalg.matrix_rank(a)
print("\nRank:", rank)

خروجی:

به دست آوردن دترمینان یک ماتریس

دترمینان یک ماتریس مربعی را می‌توان با استفاده از تابع det() پیدا کرد. این تابع هم مانند پیدا کردن مرتبه یک ماتریس متعلق به پکیچ linalg است.


import numpy as np
a = np.array([[2, 2, 1],
               [1, 3, 1],
               [1, 2, 2]])
print("a = ")
print(a)
det = np.linalg.det(a)
print("\nDeterminant:", np.round(det))

خروجی:

به دست آوردن معکوس یک ماتریس

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


import numpy as np
a = np.array([[2, 2, 1],
               [1, 3, 1],
               [1, 2, 2]])
print("a = ")
print(a)
det = np.linalg.det(a)
print("\nDeterminant:", np.round(det))
inv = np.linalg.inv(a)
print("\nInverse of a = ")
print(inv)

خروجی:

در صورتی که ماتریس شما تکین باشد (ماتریسی که دترمینان آن برابر صفر است)، (singular matrix) هر چند نمی‌توانید معکوس واقعی آن را محاسبه کنید ولی با استفاده از تابع pinv() می‌توانید شبه معکوس (pseudo inverse) آن را محاسبه کنید.


import numpy as np
a = np.array([[2, 8],
               [1, 4]])
print("a = ")
print(a)
det = np.linalg.det(a)
print("\nDeterminant:", np.round(det))
pinv = np.linalg.pinv(a)
print("\nPseudo Inverse of a = ")
print(pinv)

خروجی:

تابع ()flatten

بعضی اوقات لازم است که ماتریس موجود را به یک آرایه یک بعدی تبدیل کنید. برای انجام چنین کاری می‌توانید از تابع flatten() استفاده کنید.


import numpy as np
a = np.arange(1, 10)
a.shape = (3, 3)
print("a = ")
print(a)
print("\nAfter flattening")
print("------------------")
print(a.flatten())

خروجی:

محاسبه ویژه مقدارها و ویژه بردارهای یک ماتریس

ویژه مقدارها (eigenvalues) و ویژه بردارهای (eignvectors) یک ماتریس را می‌توان توسط تابع eig() به صورت همزمان به دست آورد.


import numpy as np
a = np.array([[2, 2, 1],
               [1, 3, 1],
               [1, 2, 2]])
print("a = ")
print(a)
w, v = np.linalg.eig(a)
print("\nEigenvalues:")
print(w)
print("\nEigenvectors:")
print(v)

خروجی: