مبانی پایتون برای علم داده – یک راهنمای مقدماتی و جامع
پایتون به عنوان یکی از زبان های اسکریپتی سطح بالا و شیءگرا کاربرد زیادی در حوزههای مختلف دارد. یکی از این حوزهها علم داده (data science) است که به طور گستردهای از امکانات این زبان برنامهنویسی قدرتمند بهره میگیرد. در این نوشته مقدمهای بر کاربردهای پایتون در علم داده ارائه کردهایم. به طور خاص تاکید بر لیستهای پایتون و همچنین بستههای مختلف موجود برای استفاده در کاربردهای مرتبط با علم داده بوده است.
انواع داده پایتون
در پایتون انواع داده مختلفی وجود دارند. رایجترین انواع دادهای به صورت float (اعشاری)، int (عدد صحیح)، str (رشتهای)، bool (بولی) و List (لیست) است.
- Float در پایتون: برای اعداد حقیقی استفاده میشود.
- Int: برای اعداد صحیح استفاده میشود.
- Str: برای متن استفاده میشود. رشتهها با استفاده از قرار دادن مقادیر داخل گیومه ‘مقدار’، گیومه دوگانه “مقدار” یا گیومه سهتایی """مقدار""" تعریف میشوند. رشتههای با گیومه سهتایی میتوانند چندین خط طول داشته باشند، کاراکتر انتهای خط (new line) نیز در مقدار متغیر لحاظ میشود. از این نوع رشتهها برای نوشتن مستندات تابع نیز استفاده میشود.
- Bool: برای مقادیر درست یا نادرست استفاده میشود. برای انجام عملیات فیلتر کردن روی دادهها مناسب است.
- List: برای ذخیرهسازی مجموعهای از مقادیر استفاده میشود.
میتوان از تابع (type (variable_name برای بررسی نوع داده یک متغیر خاص استفاده کرد. عملگرها در پایتون بسته به نوع متغیر و روشهای توکار مختلف برای هر یک، رفتار متفاوتی بروز میدهند.
لیستهای پایتون
لیست در پایتون یک نوع داده ترتیبی است. از این نوع میتوان برای ذخیره مجموعهای از مقادیر استفاده کرد. لیست میتواند شامل مقادیری از هر نوع باشد. میتوان لیستی با انواع مختلفی از دادهها در پایتون داشت؛ گرچه این مسئله چندان رایج نیست.
میتوان یک لیست جدید را با استفاده از براکت به صورت زیر نوشت:
fruits = ["pineapple", "apple", "lemon", "strawberry", "orange", "kiwi"]
تقسیم لیستها
از اندیسها میتوان برای دریافت یک عنصر یا عناصر مختلف از لیست استفاده کرد. در پایتون اندیسها از (0) آغاز میشوند؛ بنابراین نخستین عنصر اندیس (0) دارد. برای دسترسی به عناصر لیست میتوان از اندیسهای منفی نیز بهره گرفت. آخرین عنصر، اندیس (1-) دارد، یکی قبل از آخر اندیس (2-) دارد و همینطور تا آخر. همچنین چیزی به نام «قطعهبندی لیست» در پایتون وجود دارد که میتوان برای ایجاد چندین عنصر در یک لیست استفاده کرد. طرز کار از آن به صورت زیر است:
sliceable[start_index:end_index:step].
عبارت start_index اندیس آغازین یک قطعه است، عنصری که در این اندیس باشد در نتیجه خواهد آمد. مقدار پیشفرض 0 است. عبارت end_index اندیس انتهایی قطعه است. عنصری که در این اندیس باشد، در نتایج لحاظ نخواهد شد. مقدار پیشفرض طول لیست خواهد بود.
همچنین مقدار پیشفرض در صورتی که مقدار step (در بند بعدی توضیح داده شده است) منفی باشد، میتواند به صورت طول لیست منهای 1 باشد. اگر این آرگومان ذکر نشده باشد، همه عناصر از ابتدا تا انتها در نتایج گنجانده میشوند. عبارت step مقداری است که هر بار اندیس افزایش خواهد یافت. مقدار پیشفرض 1 است.
fruits = ["pineapple", "apple", "lemon", "strawberry", "orange", "kiwi"] fruits[1] # apple fruits[0] # "pineapple" fruits[-1] # "kiwi" fruits[5] # "kiwi" fruits[-3] # "strawberry" # List slicing fruits[::] # ["pineapple", "apple", "lemon", "strawberry", "orange", "kiwi"] fruits[0:2] # ["pineapple", "apple"] fruits[-2:-1] # ["orange"] fruits[3:] # ["strawberry", "orange", "kiwi"] fruits[:4] # ["pineapple", "apple", "lemon", "strawberry"] fruits[:] # ["pineapple", "apple", "lemon", "strawberry", "orange", "kiwi"] fruits[::-1] # ["kiwi", "orange", "strawberry", "lemon", "apple", "pineapple"] fruits[::-2] # ["kiwi", "strawberry", "apple"] fruits[::2] # ["pineapple", "lemon", "orange"] # Understanding some default values fruits[0:6:1] # the same result as the result from fruits[::] fruits[-1:-7:-1] # the same result as the result from fruits[::-1]
دستکاری لیست
با استفاده از متد append یا با بهرهگیری از اپراتور + میتوان مورد یا مواردی را به یک لیست اضافه نمود. اگر اپراتور + بر روی دو لیست به کار گرفته میشود، پایتون لیست جدیدی از عناصر هر دو لیست را به شما باز میگرداند. عنصر یا عناصر یک لیست را با بهرهگیری از براکتهایی که قبلاً برای اندیس گذاری و قطعهبندی لیست استفاده شد، می توان تغییر داد. همچنین با بهرهگیری از متد (remove (value میتوانید عنصری را از لیست حذف کنید. این متد نخستین عنصر لیست را با مقدار ارسالی حذف میکند.
# Add values to a list fruits.append("peach") fruits # ["pineapple", "apple", "lemon", "strawberry", "orange", "kiwi", "peach"] fruits = fruits + ["fig", "melon"] fruits # ["pineapple", "apple", "lemon", "strawberry", "orange", "kiwi", "peach", "fig", "melon"] # Change values from a list fruits[0:2] = ["grape", "mango"] fruits # ["grape", "mango", "lemon", "strawberry", "orange", "kiwi", "peach", "fig", "melon"] # Delete values from a list fruits.remove("mango") fruits # ["grape", "lemon", "strawberry", "orange", "kiwi", "peach", "fig", "melon"]
درک شیوه عمل لیستها در پشت صحنه پایتون حائز اهمیت است. زمانی که یک لیست جدید مانند my_list ایجاد میکنید، در واقع لیست را در حافظه رایانه ذخیره میکنید و نشانی این لیست در متغیر my_lisy ذخیره میشود. متغیر my_list شامل عناصر لیست نمیشود. این متغیر حاوی ارجاعی به لیست است. اگر یک لیست را صرفاً با نشانه تساوی به صورت my_list_copy = my_list کپی کنیم، تنها یک ارجاع کپی شده در متغیر my_list_copy خواهیم داشت و نه مقادیر درون لیست؛ بنابراین اگر میخواهید مقادیر واقعی یک لیست را کپی کنید باید از تابع (list (my_list یا قطعهبندی [:] استفاده کنید.
numbers = [10, 42, 28, 420] numbers_copy = numbers numbers_copy[2] = 100 numbers # [10, 42, 100, 420] numbers_copy # [10, 42, 100, 420] ratings = [4.5, 5.0, 3.5, 4.75, 4.00] ratings_copy = ratings[:] ratings_copy[0] = 2.0 ratings # [4.5, 5.0, 3.5, 4.75, 4.0] ratings_copy # [2.0, 5.0, 3.5, 4.75, 4.0] characters = ["A", "B", "C"] characters_copy = list(characters) characters_copy[-1] = "D" characters # ["A", "B", "C"] characters_copy # ["A", "B", "D"]
تابعها
تابع بخشی از کد قابل استفاده مجدد است که از آن برای حل یک مسئله خاص بهرهبرداری میشود. میتوانید تابعهای خاص خود را با استفاده از کلیدواژه def به صورت زیر بنویسید:
def is_prime(n): if n <= 1: return False elif n <= 3: return True elif n% 2 == 0 or n% 3 == 0: return False current_number = 5 while current_number * current_number <= n: if n% current_number == 0 or n% (current_number + 2) == 0: return False current_number = current_number + 6 return True
با این حال تابعهای داخلی زیادی در پایتون مانند ([max(iterable [, key]) ،min(iterable [, key]) ،type(object) ،round(number [, ndigits وجود دارند؛ بنابراین در اغلب موارد وقتی به تابعی نیاز دارید که یک مشکل خاص را حل کند، میتوانید به دنبال تابع داخلی پایتون بگردید که این مسئله را در یک بسته پایتون حل میکند. لازم نیست که چرخ را مجدداً اختراع کنید.
اغلب تابعها برخی ورودیها را میگیرند و برخی نتایج را در خروجی ارائه میکنند. این تابعها آرگومان دارند و پایتون ورودیهای ارسالی به تابع را با فراخوانی آرگومانها مطابقت میدهد. اگر در پیرامون یک آرگومان براکت آمده باشد، استفاده از آنها اختیاری است.
میتوان از تابع ([help([object یا ?function_name برای مشاهده مستندات هر تابعی استفاده کرد. در صورت بهرهبرداری از Jupyter Notebook تابع help مستنداتی در مورد سلول کنونی به شما نشان میدهد؛ در حالی که گزینه دوم مستندات را در پیجر نمایش میدهد.
متدها
در بخشهای قبلی مشاهده کردیم که در پایتون انواع داده float، integer، Boolean و مواردی از این دست را داریم و در پایتون هر یک از این ساختارهای داده، یک شیء محسوب میشوند. متد تابعی است که بسته به نوع شیء برای آن شیء مفروض وجود دارد. بدین ترتیب هر شیء یک نوع خاص و مجموعهای از متدها را بسته به این نوع دارد.
# String methods text = "Data Science" text.upper() # "DATA SCIENCE" text.lower() # "data science" text.capitalize() # "Data science" # Lists methods numbers = [1, 4, 0, 2, 9, 9, 10] numbers.reverse() numbers # [10, 9, 9, 2, 0, 4, 1] numbers.sort() numbers # [0, 1, 2, 4, 9, 9, 10]
اشیای دارای انواع متفاوت میتوانند متدهایی با نام یکسان داشته باشند. متدها بسته به نوع شیء، رفتار متفاوتی دارند.
numbers = [10, 30, 55, 40, 8, 30] text = "Data Science" numbers.index(8) # 4 text.index("a") # 1 numbers.count(30) # 2 text.count("i") # 1
مراقب باشید چون برخی متدها میتوانند اشیایی را که فراخوانی میکنند تغییر دهند. برای نمونه، متد append بسته به نوع لیست فراخوانی میشود.
بستهها
ماژول فایلی است که شامل تعاریف و عبارتهای پایتون است. ماژولها خود توابع، متدها و انواع پایتون را تعریف میکنند که برای حل مسائل خاصی استفاده میشوند. بسته در پایتون به مفهوم مجموعهای از ماژولها در دایرکتوریهای مختلف است. بستههای بسیار زیادی برای پایتون وجود دارند که برای حل مسائل مختلف عرضه شدهاند. برای مثال NumPy ، matplotlib، seaborn و scikit-learn همگی بستههای مشهوری در زمینه علم داده هستند.
- NumPy برای کار مؤثر با آرایهها استفاده میشود.
- matplotlib و seaborn کتابخانههای متداولی برای بصری سازی دادهها هستند.
- scikit-learn کتابخانه قدرتمندی برای یادگیری ماشین است.
برخی بستهها به طور پیشفرض در پایتون حضور دارند؛ اما بستههای خیلی زیادی نیز هستند که به آنها نیاز داریم و به طور پیشفرض در پایتون وجود ندارند. اگر بخواهیم از برخی بستهها استفاده کنیم یا باید از قبل روی پایتون نصب باشد و یا آن را با استفاده از pip که ابزار مدیریت بسته در پایتون است، نصب شود.
با این وجود ابزاری به نام Anaconda نیز وجود دارد. توزیع آناکوندا یک توزیع رایگان از پایتون است که ابزار مدیریت بستهها با نصب آسان، مدیر محیط و مجموعهای از بیش از 1000 بسته متن-باز با پشتیبانی رایگان دارد. بنابراین اگر نمیخواهید بستههای زیادی را نصب کنید، توصیه میکنیم که از آناکوندا استفاده کنید. بستههای بسیار زیادی در این توزیع وجود دارند.
دستورات Import
زمانی که بسته مورد نیاز شما بر روی پایتون نصب شد، میتوانید آن را درون فایلهای پایتون وارد (import) کنید. میتوان یک بسته کامل، ماژولهای فرعی یا تابعهای خاصی از آن را ایمپورت کرد. همچنین میتوان یک نام مستعار (Alias) برای بسته اضافه کرد. روشهای مختلفی که برای استفاده از دستورات Import وجود دارند، در مثالهای زیر ارائه شدهاند:
import numpy numbers = numpy.array([3, 4, 20, 15, 7, 19, 0])
دستور ایمپورت ساده
import numpy as np # np is an alias for the numpy package numbers = np.array([3, 4, 20, 15, 7, 19, 0]) # works fine numbers = numpy.array([3, 4, 20, 15, 7, 19, 0]) # NameError: name 'numpy' is not defined
عبارت ایمپورت با Alias
# import the "pyplot" submodule from the "matplotlib" package with alias "plt" import matplotlib.pyplot as plt
ایمپورت کردن ماژولهای فرعی از یک بسته با استفاده از Alias
from numpy import array numbers = array([3, 4, 20, 15, 7, 19, 0]) # works fine numbers = numpy.array([3, 4, 20, 15, 7, 19, 0]) # NameError: name 'numpy' is not defined type(numbers) # numpy.ndarray
ایمپورت کردن تنها یک تابع از یک بسته
میتوان دستوری به صورت * from numpy import نوشت. نشان ستاره در این دستور به آن معنی است که همه عناصر این ماژول وارد میشود. این دستور ایمپورت، ارجاعهایی در فضای نام کنونی به همه اشیای عمومی تعریف شده از سوی ماژول numpy ایجاد میکند. به بیان دیگر میتوانید به همه تابعهای موجود در numpy در این ماژول بدون هیچ گونه پیشوندی دسترسی داشته باشید. برای نمونه در این حالت میتوانید از تابع absolute در NumPy به صورت ()absolute استفاده کنید و نه ()numpy.absolute.
با این حال این روش به دلایل زیر توصیه نمیشود:
- اگر همه تابعهای ماژولهای این چنین را ایمپورت کنید، در فضای نام جاری آنقدر تابعهای مختلف اشباع میشوند که اگر فرد دیگری به کد شما نگاه کند، ممکن است سردرگم شود که یک تابع خاص به کدام بسته تعلق دارد.
- اگر دو ماژول تابعهایی با نام یکسان داشته باشند، ایمپورت ماژول دوم، ایمپورت اولی را باطل میکند.
NumPy
ماژول NumPy یک بسته بنیادی برای محاسبات علمی در پایتون محسوب میشود. این بسته بسیار سریع و استفاده از آن آسان است. این بسته به انجام محاسباتی در سطح عناصر آرایه (عنصر به عنصر) کمک میکند. در لیست معمولی پایتون امکان اجرای اپراتورهایی در سطح عناصر وجود ندارد. البته میتوانیم از لیستهای پایتون استفاده کنیم، اما آنها کند هستند و برای رسیدن به نتیجه مشابه به کد بیشتری نیاز داریم. تصمیم بهتر در اغلب موارد این است که از بسته NumPy استفاده کنیم.
آرایهها در NumPy برخلاف لیستهای معمولی پایتون تنها یک نوع میپذیرند. اگر آرایهای با انواع دادهای مختلف را به ()np.array بفرستید، میبایست با استفاده از پارامتر dtype نوع مورد نیاز را ذکر کنید. اگر این پارامتر ارائه نشود در این صورت نوع موردنظر به صورت کمترین نوع مورد نیاز برای نگهداری اشیا تعیین میشود.
np.array([False, 42, "Data Science"]) # array(["False", "42", "Data Science"], dtype="<U12") np.array([False, 42], dtype = int) # array([0, 42]) np.array([False, 42, 53.99], dtype = float) # array([0., 42., 53.99]) # Invalid converting np.array([False, 42, "Data Science"], dtype = float) # could not convert string to float: 'Data Science'
آرایه NumPy – تبدیل نوع
آرایه NumPy با خصوصیات و متدهای خاص خود عرضه میشود. به خاطر داشته باشید که اپراتورها در پایتون بر روی انواع مختلف دادهها به روشی متفاوت عمل میکنند. در NumPy اپراتورها در سطح عناصر عمل میکنند.
np.array([37, 48, 50]) + 1 # array([38, 49, 51]) np.array([20, 30, 40]) * 2 # array([40, 60, 80]) np.array([42, 10, 60]) / 2 # array([21., 5., 30.]) np.array([1, 2, 3]) * np.array([10, 20, 30]) # array([10, 40, 90]) np.array([1, 2, 3]) - np.array([10, 20, 30]) # array([-9, -18, -27])
اگر نوع آرایه NumPy را بررسی کنیم، نتیجه به صورت numpy.ndarray خواهد بود. Ndarray به معنی آرایه n-بُعدی است. در مثالهای فوق از آرایههای 1 بعدی استفاده شده است؛ اما مانعی برای استفاده از آرایههای 2، 3، 4 و یا با ابعاد بالاتر وجود ندارد. امکان تقسیم کردن یک آرایه صرفنظر از ابعاد آن وجود دارد. مثالهایی از آرایههای 2 بعدی در ادامه ارائه شده است:
numbers = np.array([ [1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12] ]) numbers[2, 1] # 8 numbers[-1, 0] # 10 numbers[0] # array([1, 2, 3]) numbers[:, 0] # array([1, 4, 7, 10]) numbers[0:3, 2] # array([3, 6, 9]) numbers[1:3, 1:3] # array([[5, 6], [8, 9]])
اگر بخواهید ببینید که یک آرایه چه ابعاد و چه تعداد عناصر دارد، میتوانید از خصوصیت shape استفاده کنید. در مورد آرایههای 2-بُعدی نخستین عنصر چندتایی، تعداد ردیفها و عدد دوم، تعداد ستونها خواهد بود.
numbers = np.array([ [1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15] ]) numbers.shape # (5, 3)
آمار مقدماتی
نخستین گام در تحلیل دادهها آشنایی با آن دادهها است. NumPy متدهای زیادی دارد که به انجام این کار کمک میکنند. در ادامه برخی متدهای ساده برای انجام محاسبات آماری بر روی دادهها را مشاهده میکنید:
- ()np.mean: این متد میانگین حسابی مجموعه عناصر را باز میگرداند. منظور از میانگین حسابی مجموع همه عناصر تقسیم بر تعداد عناصر است.
- ()np.median: میانه عناصر را باز میگرداند. منظور از میانه مقدار عنصر میانی یک آرایه است. اگر طول آرایه فرد باشد، این عنصر مشخص است و اگر طول آن زوج باشد میانگین دو عنصر میانی محاسبه میشود.
- ()np.corrcoef: یک ماتریس همبستگی باز میگرداند. این تابع زمانی مفید است که بخواهیم ببینیم آیا بین متغیرهای یک مجموعه داده همبستگی وجود دارد یا نه. به بیان دیگر این متد وجود همبستگی بین دو آرایه با طول یکسان را بررسی میکند.
- ()np.std: انحراف معیار را محاسبه میکند.
learning_hours = [1, 2, 6, 4, 10] grades = [3, 4, 6, 5, 6] np.mean(learning_hours) # 4.6 np.median(learning_hours) # 4.0 np.std(learning_hours) # 3.2 np.corrcoef(learning_hours, grades) # [[1. 0.88964891][0.88964891 1.]]
در مثال فوق میبینیم که همبستگی بالایی بین ساعتهای یادگیری و نمرههای دانشجویان وجود دارد. همچنین موارد زیر را ملاحظه میکنیم:
- میانگین ساعتهای یادگیری برابر با 4.6 است.
- میانه ساعتهای یادگیری 4.0 است.
- انحراف معیار ساعتهای یادگیری برابر با 3.2 است.
NumPy برخی تابعهای پایهای مانند ()np.sort و ()np.sum نیز دارد که در لیستهای مقدماتی پایتون به کار میآیند. نکته مهمی که در اینجا باید اشاره کنیم آن است که NumPy الزام میکند که در هر آرایه تنها از یک نوع داده استفاده شود و به همین دلیل سرعت محاسبات بالاتر میرود.
اگر این نوشته مورد توجه شما واقع شده است، پیشنهاد میکنیم موارد زیر را نیز ملاحظه نمایید:
- آموزش برنامه نویسی پایتون – مقدماتی
- علم داده چیست؟
- یادگیری ماشین (Machine Learning) با پایتون (Python)
- مجموعه آموزشهای برنامهنویسی
- علم داده، تحلیل داده، دادهکاوی و یادگیری ماشین ــ تفاوتها و شباهتها
- چگونه یک دانشمند داده شوید؟ — راهنمای گامبهگام به همراه معرفی منابع
- مجموعه آموزشهای علوم کامپیوتر
==