یکی از سؤالات رایج در زمینه یادگیری «علم داده‌ها» (Data Science) و «یادگیری ماشین» (Machine Learning)، این است که برای تبدیل‌شدن به یک «داده پژوه» (Data Scientist)، چه میزان آشنایی با ریاضیات نیاز است؟ اگرچه این سؤال، ساده به نظر می‌رسد؛ جواب آسانی برای آن وجود ندارد. معمولاً، به علاقه‌مندان یادگیری حوزه علم داده‌ها گفته می‌شود که برای شروع یادگیری این حوزه، باید با مفاهیم پایه‌ای آمار توصیفی و استنباطی آشنا شوند. یادگیری این مفاهیم برای شروع کار، بسیار مناسب است.

برای اینکه با مفاهیم پایه‌ای یادگیری ماشین آشنا شوید، نیاز به یادگیری بیشتر مفاهیم ریاضی خواهید داشت. شما باید نحوه کارکرد الگوریتم‌های مختلف، محدودیت‌های آن‌ها و فرضیات اساسی اتخاذشده برای آن‌ها را درک کنید. در ابتدای کار، حوزه‌های بسیار زیادی از قبیل جبر، حسابان، آمار، هندسه سه‌بعدی و … برای مطالعه وجود دارند.

اگر شما نیز مانند خیلی از افراد، در انتخاب حوزه مورد نیاز خود برای شروع کار سردرگم شده‌اید، پیشنهاد می‌کنیم با یادگیری جبر خطی شروع کنید. با این وجود، مشکل به همین‌جا ختم نمی‌شود و باید بدانید که چگونه جبر خطی را یاد بگیرید. اگر با نحوه صحیح یادگیری این موضوع آشنا نشوید، احتمالاً در بسیاری از جزئیات و مشتقات ریاضی آن غرق خواهید شد و این مسئله، هیچ کمکی به یادگیری شما نخواهد کرد.

در این مقاله، به شما کمک می‌کنیم تا با نحوه یادگیری صحیح و مباحث مهم جبر خطی آشنا شوید. با ما همراه باشید.

فهرست مطالب

1- چرا باید جبر خطی را بیاموزیم؟
2- نمایش مسائل در جبر خطی
1-2- تصویرسازی مسئله: خط
2-2- معرفی مسائل پیچیده‌تر
3-2- صفحه
3- ماتریس
1-3- اصطلاحات مرتبط با ماتریس
2-3- عملیات اصلی در ماتریس
3-3- نمایش مسئله در فرم ماتریسی
4- حل مسئله
1-4- فرم سطری پلکانی
2-4- معکوس ماتریس
1-2-4- یافتن معکوس ماتریس
2-2-4- قدرت ماتریس‌ها: حل معادلات در یک مرحله
3-2-4- استفاده از معکوس ماتریس در علم داده‌ها
5- بردارهای ویژه و مقادیر ویژه
1-5- یافتن بردارهای ویژه
2-5- استفاده از بردارهای ویژه در علم داده‌ها: الگوریتم تحلیل مؤلفه‌های اصلی (PCA)
6- تجزیۀ مقدارهای منفرد یک ماتریس
7- سخن پایانی

1- چرا باید جبر خطی را بیاموزیم؟

اگر در حال یادگیری علم داده‌ها و یادگیری ماشین هستید، چهار سناریوی مختلف را برای شما ارائه می‌کنیم تا متوجه شوید که چرا باید جبر خطی را یاد بگیرید؟

سناریوی اول:

به تصویر بالا نگاه کنید. چه چیزی در این تصویر می‌بینید؟ احتمالاً، پاسخ اکثر شما، یک گل و برگ‌های آن است. پاسخ به این سؤال، خیلی دشوار نبود اما اگر از شما بخواهیم که کدی را بنویسید تا کامپیوتر، تصویر مشابهی را نمایش دهد، کار بسیار سختی پیش روی شما خواهد بود (حتی بیان آن نیز کار سختی است).

شما می‌توانید گل را درون تصویر تشخیص دهید. زیرا مغز انسان در طی میلیون‌ها سال تکامل یافته است و اکنون قادر به تشخیص چنین چیزی است. ما از عملیاتی که در پس‌زمینه مغزمان صورت می‌گیرد و ما را قادر می‌سازد رنگ‌های درون تصویر را تشخیص دهیم، اطلاعی نداریم. مغز ما، به نحوی آموزش دیده است که به صورت خودکار، این کار را برای ما انجام دهد.

اگر بخواهیم کاری کنیم که یک کامپیوتر نیز قادر به انجام چنین چیزی باشد، آسان نیست. این مسئله، یکی از حوزه‌های تحقیقاتی فعال در علم دادها و یادگیری ماشین است. قبل از کار بر روی تشخیص ویژگی‌های یک تصویر، بگذارید بر روی یک سؤال خاص تمرکز کنیم: «چگونه یک کامپیوتر یا ماشین، این تصویر را ذخیره می‌کند؟»

احتمالاً می‌دانید که کامپیوترهای امروزی، برای پردازش تنها دو عدد 0 و 1 طراحی شده‌اند. حال، چگونه تصویری مانند مثال بالا به همراه ویژگی‌های مختلف، می‌تواند در یک کامپیوتر ذخیره شود؟ این کار با ذخیره‌سازی شدت پیکسل‌ها در ساختاری به نام «ماتریس» صورت می‌گیرد. به این ترتیب، هر عملی که بخواهید بر روی این تصویر انجام دهید، به احتمال زیاد از قواعد جبر خطی و ماتریس‌ها در پس‌زمینه خود استفاده خواهد کرد.

سناریوی دوم:

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

سناریوی سوم:

«یادگیری عمیق»، یک عبارت فراگیر جدید در حوزه به کارگیری ماتریس‌ها به منظور ذخیره ورودی‌هایی مانند تصویر، گفتار یا متن و ارائه یک راه‌حل برای مسائل این‌چنینی است. وزن‌های به‌دست‌آمده توسط یک شبکه عصبی نیز در ماتریس‌ها ذخیره می‌شوند. در تصویر زیر، نمونه‌ای از نمایش گرافیکی وزن‌های ذخیره‌شده در یک ماتریس نشان داده شده است.سناریوی چهارم:

یکی دیگر از زمینه‌های تحقیقاتی فعال در حوزه یادگیری ماشین، نحوه کار با متن است. رایج‌ترین تکنیک‌های مورد استفاده در این زمینه، «کیسه کلمات» (Bag of Words)، «ماتریس لغت-سند» (Term Document Matrix) و غیره هستند. تمام این تکنیک‌ها، به صورت بسیار مشابهی عمل می‌کنند. به این صورت که شمارش کلمات در اسناد را انجام داده و به منظور اجرای عملیاتی مانند تحلیل معنایی، ترجمه زبان، خلق زبان و غیره، تعداد تکرار کلمات را در یک فرم ماتریسی ذخیره می‌کنند.

اکنون می‌توانید میزان اهمیت جبر خطی در یادگیری ماشین را درک کنید. مشاهده کردیم که تصویر، متن یا هر داده دیگری، از ماتریس‌ها برای ذخیره‌سازی و پردازش داده‌ها استفاده می‌کنند. همین موضوع می‌تواند انگیزه کافی برای یادگیری جبر خطی را در شما به وجود آورده باشد. آموزش ارائه‌شده در این مقاله، نسبتاً طولانی است اما جبر خطی را از پایه برای شما توضیح خواهد داد.

2- نمایش مسائل در جبر خطی

بیایید تعریف مسائل جبر خطی را با یک مثال ساده شروع کنیم. فرض کنید قیمت یک توپ و دو راکت یا یک راکت و دو توپ، 100 واحد باشد. حال باید قیمت یک توپ و یک راکت را بیابیم. قیمت یک راکت را با «x» و قیمت یک توپ را «y» نشان می‌دهیم. مقدار x و y بسته به شرایط می‌تواند هر چیزی باشد. این یعنی x و y متغیر هستند.

فرم ریاضی این مسئله را به صورت زیر می‌نویسیم:

(1) 2x + y = 100

حالت دوم را نیز به همین صورت می‌نویسیم:

(2) x + 2y = 100

حال برای پیدا کردن قیمت توپ و راکت، باید مقادیر x و y را طوری به دست بیاوریم که هر دو معادله ارضا شوند. مسئله اصلی در جبر خطی، پیدا کردن مقادیر x و y است (حل یک دستگاه معادلات خطی). به طور کلی در جبر خطی، داده‌ها به صورت معادلات خطی نشان داده می‌شوند. این معادلات خطی نیز در فرم ماتریسی و برداری نشان داده می‌شوند. تعداد متغیرها و همچنین تعداد معادلات با توجه به شرایط تغییر می‌کنند اما نمایش آن‌ها به صورت ماتریسی و برداری خواهد بود.

1-2- تصویرسازی مسئله

معمولاً رسم گرافیکی و تصویرسازی، به حل تصویرسازی مسائل کمک می‌کند. معادلات خطی، اشیا مسطح را نشان می‌دهند. برای درک بهتر، از ساده‌ترین نوع این اشیا شروع می‌کنیم. خط مربوط یک معادله، مجموعه‌ای از نقاطی است که در معادله داده‌شده صدق می‌کنند. به عنوان مثال، نقاط (50,0)، (0,100)، (100/3,100/3) و (30,40) در معادله 1 ما صدق می‌کنند. در نتیجه، این نقاط باید بر روی خط مرتبط با معادله 1 ما قرار گیرند. به همین صورت، (50,0)، (0,100) و (100/3,100/3)، تعدادی از نقاطی هستند که در معادله 2 صدق می‌کنند.

در این شرایط، می‌خواهیم هر دو معادله ما ارضا شوند. برای این کار، باید نقطه‌ای را پیدا کنیم که در هر دو معادله صدق می‌کند. از نظر تصویری، ما به دنبال تقاطع دو خط معرف معادلات 1 و 2 هستیم (تصویر پایین).

بگذارید با استفاده از عملیات ابتدایی جبری مانند جمع، تفریق و جایگذاری، این مسئله را حل کنیم.

(1) 2x + 2y = 100

حالت دوم را نیز به همین صورت می‌نویسیم:

(2) X + 2y = 100

از معادله 1 داریم:

y = (100 – x) / 2

مقدار y را درون معادله 2 قرار می‌دهیم:

(3) X + 2 * (100 – x) / 2 = 100

از آنجایی که معادله 3 یک معادله یک مجهولی است، برای x و y به راحتی قابل حل است. این مسئله آسان بود. اکنون به یک مرحله بالاتر می‌رویم.

2-2- معرفی مسائل پیچیده‌تر

فرض کنید یک دستگاه با سه معادله و سه مجهولی (مانند زیر) به شما داده شده است و می‌خواهید مقادیر تمام متغیرها را به دست بیاورید. بیایید این مسئله را با هم حل کنیم:

(4) x + y + z = 1

(5) 2x + y = 1

(6) 5x + 3y + 2z = 4

از معادله 4 داریم:

(7) z = 1 – x – y

با جایگذاری z در معادله 6 داریم:

5x + 3y + 2(1 – x – y) = 4

(8) 3x + y = 2

اکنون می‌توان معادله 8 و 5 را برای به دست آوردن مقادیر x و y به صورت یک دستگاه با دو معادله و دو مجهول، مانند مثال توپ و راکت حل کرد. بعد از یافتن x و y، می‌توان از معادله 7 برای به دست آوردن مقدار z استفاده کرد.

همان‌طور که مشاهده کردید، با اضافه کردن یک متغیر دیگر، تلاش برای پیدا کردن حل مسئله به میزان زیادی افزایش یافت. حل هم‌زمان 10 معادله، بسیار دشوار، خسته‌کننده و زمان‌بر خواهد بود. اگر مسائل مرتبط علم داده‌ها را در نظر بگیریم، میلیون‌ها داده در هر مسئله وجود خواهد داشت.

فرض کنید، میلیون‌ها داده در یک مجموعه داده واقعی داریم. استفاده از رویکرد بالا برای به دست آوردن جواب، بیشتر شبیه به یک کابوس خواهد بود تا یک راه‌حل. حال فرض کنید که قرار است این کار را چندین و چند بار انجام دهیم. مطمئناً، سال‌های طول می‌کشد تا این مسئله را حل کنیم. این تنها بخشی از کار در مسائل مرتبط با علوم داده است. چه کار باید انجام دهیم؟ به نظر شما، باید حل این‌گونه مسائل را به کلی کنار بگذاریم؟ پاسخ منفی است.

برای حل یک دستگاه معادلات خطی بزرگ، از ماتریس استفاده می‌کنیم. قبل از اینکه به سراغ تعریف ماتریس و ویژگی‌های آن برویم، بیایید تصویر فیزیکی مسئله خود را در نظر بگیریم. برای این کار، نیاز به تعاریفی داریم که در ادامه به آن‌ها می‌پردازیم.

3-2- صفحه

یک معادله خطی با سه متغیر (سه مجهولی)، مجموعه‌ای از نقاطی را نشان می‌دهد که در معادلات مربوط به خود صدق می‌کنند. آیا می‌توانید، شی‌ء فیزیکی معرف چنین معادله‌ای را حدس بزنید؟ سعی کنید شی‌ء معرف یک معادله با دو متغیر را در نظر بگیرید (خط) و سپس، متغیر سوم را به آن اضافه کنید. باید متوجه شده باشید که با اضافه شدن متغیر سوم، معادل سه‌بعدی خط به وجود می‌آید.

اساساً، یک معادله خطی با سه متغیر، معرف یک صفحه است. از نظر فنی، یک صفحه، شی‌ء هندسی مسطحی است که تا بی‌نهایت گسترش می‌یابد. برای پیدا کردن جواب‌های دستگاه معادلات خطی سه مجهولی، باید تقاطع بین صفحات معرف هر معادله را پیدا کنیم (مانند کاری که برای خط انجام دادیم). به طور کلی، چهار حالت برای نحوه تقاطع بین سه صفحه وجود دارد:

  1. تقاطعی با هم ندارند.
  2. هر سه در یک خط تقاطع می‌یابند.
  3. در یک صفحه باهم تقاطع می‌یابند.
  4. در یک نقطه باهم تقاطع می‌یابند.

انسان‌ها، تنها توان تصور سه بعدی اشیاء مختلف را دارند و تصور اشیاء در 4 یا 10,000 بعد، برایشان غیرممکن است. با این حال، ریاضیدانان توسط به کارگیری یک سری ترفند، با داده‌هایی با ابعاد بالا به راحتی کار می‌کنند؛ یکی از این ترفندها، استفاده ماتریس است.

3- ماتریس

ماتریس، روشی برای نوشتن مؤلفه‌های مشابه در کنار یکدیگر است تا بتوان با توجه به موارد مورد نیاز، آن‌ها را به راحتی بررسی و تغییرات لازم را ایجاد کرد. به طور کلی در علم داده‌ها، به منظور ذخیره اطلاعاتی مانند وزن‌های شبکه عصبی مصنوعی در حین آموزش الگوریتم‌های مختلف، از ماتریس استفاده می‌شود.

اساساً ماتریس، یک آرایه دوبعدی از اعداد است (البته تا جایی که به حوزه علم داده‌ها مرتبط می‌شود). برای مثال، به ماتریس زیر نگاه کنید:

معمولاً، سطرها را با «i» و ستون‌ها را با «j» علامت‌گذاری می‌کنند. درایه‌ها با سطر i ام و ستون j ام نمایه می‌شوند. نام‌گذاری ماتریس‌ها نیز به وسیله حروف الفبای لاتین صورت می‌گیرد. مثال: ماتریس A با درایه‌های Aij

در ماتریس بالا، درایه A12 برابر است با 2. برای پیدا کردن این درایه، باید به سطر اول و ستون دوم بروید (A12 = 2).

3-1- اصطلاحات مرتبط با ماتریس

  • مرتبه ماتریس: اگر یک ماتریس دارای 3 سطر و 4 ستون باشد، مرتبه آن 4*3 است. ستون*سطر=نمایش مرتبه
  • ماتریس مربعی: ماتریسی که تعداد سطرهای آن با تعداد ستون‌هایش برابر باشد.
  • ماتریس قطری: ماتریسی که تمامی درایه‌هایش، به غیر از درایه‌های روی قطر اصلی آن، صفر باشند.
  • ماتریس بالا مثلثی: یک ماتریس مربعی که تمام درایه‌های پایین قطر اصلی آن صفر است.
  • ماتریس پایین مثلثی: یک ماتریس مربعی که تمام درایه‌های بالای قطر اصلی آن صفر است.
  • ماتریس همانی: یک ماتریس مربعی که درایه‌های قطر اصلی آن برابر با 1 بوده و باقی درایه‌ها برابر با صفر هستند.
  • ماتریس ستونی: ماتریسی که تنها دارای یک ستون است. گاهی اوقات برای نمایش بردارها، از ماتریس ستونی استفاده می‌شود.
  • ماتریس سطری: ماتریسی که تنها دارای یک سطر است.
  • اثر ماتریس: جمع درایه‌های قطر اصلی یک ماتریس مربعی است.

2-3- عملیات اصلی در ماتریس

جمع ماتریس:

جمع ماتریس، تقریباً مشابه با جمع پایه‌ای در ریاضیات است. تنها نکته این است که باید مرتبه همه ماتریس‌ها مانند یکدیگر باشد. هنگتم جمع دو ماتریس، خود شما متوجه این نکته خواهید شد.

فرض کنید، دو ماتریس «A» و «B» را داشته باشیم و نتیجه جمع این دو ماتریس را با «C» نشان دهیم؛ بنابراین داریم:

Cij = Aij + Bij

بیایید برای مثال، جمع این دو ماتریس را انجام دهیم.

نتیجه جمع این دو می‌شود:

مشاهده می‌کنید که برای به دست آوردن درایه‌های ماتریس C، درایه‌های متناظر ماتریس‌های A و B با هم جمع شده‌اند.

ضرب عددی یا اسکالر:

ضرب یک ماتریس با یک ثابت عددی را «ضرب اسکالر» می‌گوییم. برای انجام ضرب اسکالر، باید عدد ثابت را در هر یک از درایه‌های ماتریس داده‌شده ضرب کنیم. فرض کنید، عدد ثابت «c» را داشته باشیم و آن را در ماتریس «A» ضرب کنیم. نتیجه ضرب اسکالر c در A می‌شود:

c[Aij] = [c * Aij]

ترانهاده:

با عوض کردن درایه‌های سطرها با درایه‌های ستون‌های یک ماتریس، ترانهاده آن به دست می‌آید. به عنوان مثال:

AijT= Aji

برای اجرای برداری رگرسیون منطقی و خطی، از ماتریس ترانهاده استفاده می‌شود.

کد ماتریس ترانهاده در زبان برنامه‌نویسی پایتون (Python):

array([[21, 22, 23],
[24, 25, 26],
[27, 28, 29]])

array([[21, 24, 27],
[22, 25, 28],
[23, 26, 29]])

ضرب ماتریس:

یکی از پرتکرارترین عملیات مورد استفاده در جبر خطی، ضرب ماتریسی است. با یادگیری خصوصیات مهم ماتریس، قادر خواهیم بود تا دو ماتریس را در هم ضرب کنیم. قبل از ارائه الگوریتم این کار، چند نکته وجود دارند که باید آن‌ها را به خاطر بسپارید:

  1. ضرب دو ماتریس با مرتبه‌های i*j و j*k، ماتریسی با مرتبه i*k خواهد بود. برای به دست آوردن مرتبه ماتریس نهایی، فقط نمایه‌های کناری را نگه دارید.
  2. دو ماتریس تنها زمانی قابل ضرب هستند که تعداد ستون‌های ماتریس اول با تعداد سطرهای ماتریس دوم برابری کند.
  3. مرتبه ضرب بسیار مهم است.

اگر مفهوم این نکات را درک نکردید، اصلاً نگران نباشید. در انتهای این بخش، متوجه تمام نکات خواهید شد.

فرض کنید، بخواهیم دو ماتریس A و B را در یکدیگر ضرب کنیم. تصویر زیر نتیجه ضرب این دو ماتریس را با توجه به تقدم و تأخر آن‌ها نشان می‌دهد. در ادامه، مراحل رسیدن به این نتیجه را شرح می‌دهیم.

با توجه به نکته اول، می‌دانیم که ماتریس نهایی ما دارای مرتبه 3*3 است. از این‌رو، یک ماتریس 3*3 می‌سازیم. برای تعیین کردن درایه AB)ij)، هر درایه سطر i ام ماتریس A را در تمام درایه‌های ستون j ام ماتریس B ضرب می‌کنیم و عبارت‌های ضرب‌شده را با هم جمع می‌کنیم (به تصویر بالا نگاه کنید). برای درک بهتر ضرب درایه به درایه، به کد زیر نگاه کنید:

AB= array([[2250, 2316, 2382],
[2556, 2631, 2706],
[2862, 2946, 3030]]) B.dot(A)

BA= array([[2310, 2406, 2502],
[2526, 2631, 2736],
[2742, 2856, 2970]])

در این کد، درایه اول، 2250 است. نتیجه این درایه به صورت 2250=21*31+22*34+23*37 به دست آمده است. دیگر درایه‌ها نیز به همین شکل به دست می‌آیند. به تفاوت بین نتیجه ضرب AB و BA توجه کنید.

ویژگی‌های ضرب ماتریس:

1- ضرب ماتریسی دارای خاصیت شرکت‌پذیری دارد؛ یعنی

array([[306108, 313056, 320004],
[347742, 355635, 363528],
[389376, 398214, 407052]])

array([[306108, 313056, 320004],
[347742, 355635, 363528],
[389376, 398214, 407052]])

2- ضرب ماتریسی، خاصیت جابجایی ندارد؛ یعنی AB با BA برابر نیست.

ضرب ماتریسی در رگرسیون منطقی و خطی، هنگامی استفاده می‌شود که ما از روش بردار پارامتریک برای محاسبه مقدار متغیر خروجی استفاده می‌کنیم. حال که مبانی مرتبط با ماتریس را یاد گرفتیم، وقت به کارگیری آن‌ها رسیده است.

3-3- نمایش مسئله در فرم ماتریسی

یک کاغذ و خودکار بردارید و سعی کنید مقدار ضرب ماتریسی زیر را به دست آورید.

با صراحت می‌توان گفت که عبارت بالا، سه معادله خط ما را در خود جای داده است. ماتریس‌های خود را با حروف «A»، «X» و «Z» نام‌گذاری می‌کنیم. می‌توانیم، معادلات خود را به صورت یکجا بنویسیم:

AX = Z

در ادامه‌ی این مقاله و در بخش دوم، به آموزش روش حل معادلات به کمک ماتریس‌ها می پردازیم و مفاهیم پیشرفته جبر خطی و کاربرد آنها در علم داده‌ها را مورد بررسی قرار خواهیم داد.

اگر تمایل به مطالعه بیشتر در مورد این موضوعات را داشته باشید؛ شاید آموزش های زیر نیز برای شما مفید باشند:

#

حسین زبرجدی دانا (+)

«حسین زبرجدی دانا»، کارشناس ارشد مهندسی استخراج معدن است. فعالیت‌های علمی او در زمینه تحلیل عددی سازه‌های مهندسی بوده و در حال حاضر آموزش‌های مهندسی عمران، معدن و ژئوتکنیک مجله فرادرس را می‌نویسد.

بر اساس رای 14 نفر

آیا این مطلب برای شما مفید بود؟

3 نظر در “کاربرد جبر خطی در علم داده‌ها و یادگیری ماشین — بخش اول

  1. سلام من میخوام راجب کاربرد جبر خطی یک پروژه تهییه کنم بنظرتون این یادگیری ماشین میتونه مناسب باشه برای پروژه جبر

  2. با سلام و ممنون از مطالب مفیدتان
    خواهشمند است در صورت امکان کتابی چه به بصورت انگلیسی و یا به فارسی در زمینه جبر خطی برای درک بهتر روابط جبری مورد استفاده در حوزه یادگیری ماشین معرفی کنید. با تشکر

  3. سلام
    مطلب بسیار مفیدی بود برای کسانی که می‌خواهند این مسیر را شروع کنند.
    لطفا در صورت امکان معادل انگلیسی اصطلاحات به کار رفته در این پست و پست‌های مشابه را قرار دهید تا دوستان در برخورد با متن‌ها و آموزش‌های انگلیسی دچار سر در گمی نشوند.

نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *