منبع اصلی نوشتار زیر در این لینک قرار دارد

با R و یک الگوریتم نسبتا ساده موبایل انتخاب کنید

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

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

الگوریتم TOPSIS

TOPSIS مخفف این عبارت است:

Technique for Order of Preference by Similarity to Ideal Solution

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

  • در این روش m گزینه داریم.
  • گزینه‌ای را می‌خواهیم که نزدیک‌ترین فاصله به ایده‌آل مثبت و بیشترین فاصله از ایده‌آل منفی را دارد.

پیاده‌سازی این الگوریتم در R نسبتا ساده است و فقط نیاز به کمی محاسبات ماتریسی دارد(به همین دلیل پیاده‌سازی آن در متلب و پایتون و زبان‌های مشابه هم احتمالا آسان خواهد بود.). در صفحه ویکیپدیای این الگوریتم می‌توانید مراحل آن را مشاهده کنید. در قالب یک مثال این الگوریتم را مرحله به مرحله اجرا می‌کنیم:

فرض کنید شخصی می‌خواهد از بین سه گوشی LG G5، LG v10 و گالاکسی S7 یک مورد را انتخاب کند.(پی‌نوشت ۱) او معیارهای زیر را برای تصمیم‌گیری انتخاب نموده است:

معیارهای مثبت معیارهای منفی
اندازه‌ی صفحه وزن
مگاپیکسل دوربین قیمت
شارژدهی هنگام اینترنت
قدرت نسبی پردازنده
طراحی

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

مرحله اول: جمع‌آوری اطلاعات

با کمک سایت gsmArena اطلاعات مورد نیاز را جمع می‌کنیم و در جدول زیر می‌نویسیم:

طراحی قیمت وزن cpu شارژدهی اینترنت دوربین اندازه صفحه معیار|گزینه
خیلی‌خوب ۵۹۹ ۱۵۹ خیلی‌خوب ۴۵۵ ۱۶ ۵.۳ G5
خوب ۶۹۹ ۱۹۲ خوب ۵۷۴ ۱۶ ۵.۷ V10
خیلی‌خوب ۶۴۹ ۱۵۲ خیلی‌خوب ۵۰۰ ۱۲ ۵.۱ s7

قدم بعدی تبدیل جدول بالا به یک ماتریس است که بتوان روی آن عملیات ریاضی انجام داد، برای این کار باید به نحوی معیارهای نسبی را به معیارهای کمی تبدیل کنیم، راه‌حل رایج در mcdm نسبت‌دادن یک عدد به صفاتی است که استفاده کرده‌ایم، مثلا خیلی‌خوب برابر ۹ و خوب برابر ۷ و به همین ترتیب خیلی بد برابر ۱ می‌شود، جدول بالا را با این فرض اصلاح می‌کنیم:

طراحی قیمت وزن cpu شارژدهی اینترنت دوربین اندازه صفحه معیار|گزینه
۹ ۵۹۹ ۱۵۹ ۹ ۴۵۵ ۱۶ ۵.۳ G5
۷ ۶۹۹ ۱۹۲ ۷ ۵۷۴ ۱۶ ۵.۷ V10
۹ ۶۴۹ ۱۵۲ ۹ ۵۰۰ ۱۲ ۵.۱ s7

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

x <- matrix(c(5.3,5.7,5.1,16,16,12,455,574,500,9,7,9,159,192,152,599,699,649,9,7,9),nrow = 3)

اگر کمی به دستور بالا دقت کنید متوجه می‌شوید که داده‌های ماتریس به ترتیب ستونی نوشته‌ شده‌اند، این ترتیب در R و بسیاری از نرم‌افزارهای آماری ترتیب پیش‌فرض است، اگر خواستید به ترتیب ردیفی داده‌ها را وارد کنید بعد از nrow = 3 عبارات byrow= T را وارد کنید.

برای راحتی کار با دستور زیر نام‌های ستون‌‌های جداول بالا را نیز به ماتریس خود اضافه می‌کنیم:

colnames(x) <- c("screen","MP","charge","cpu","weight","price","design")

و با دستور زیر نام گزینه‌ها را به ماتریس اضافه می‌کنیم:

rownames(x) <- c("g5","v10","s7")

در حال حاضر اگر x را تایپ کنید و اینتر بزنید احتمالا باید ماتریس x را به شکل زیر در کنسول ببینید:

topsis-x

قدم دوم، نرمال‌سازی ماتریس تصمیم‌گیری

معیارهای ما در این مثال و تقریبا تمامی مسائلی که در تصمیم‌گیری پیش می‌آید مقیاس‌های متفاوتی دارند، مثلا مقیاس یکی گرم است و مقیاس دیگری واحد پول، به همین دلیل نیاز است تا به نحوی این مقیاس‌ها را از بین ببریم، از طرف دیگر دامنه معیارها هم با هم متفاوت است، مثلا یک اعداد یکی از معیارها بین ۰ تا ۱۰ قرار دارند و اعداد دیگری بین ۴۰۰ و ۶۰۰، به همین دلیل با عملیاتی به نام نرمال‌سازی از شر این مشکلات خلاص می‌شویم. راه‌های زیاد برای نرمال‌سازی یا بی‌مقیاس‌کردن وجود دارد، برای این مثال از روشی به نام نرم استفاده می‌کنیم که در آن از فرمول زیر استفاده می‌شود:

norm

این فرمول در واقع هر عنصر ماتریس را بر جذر مجموع مجذورات همان ستون از ماتریس تقسیم می‌کند. با دستور زیر این کار را در R انجام می‌دهیم و آن را در ماتریسی به نام r ذخیره می‌کنیم:

r <- t(t(x)/sqrt(colSums(x^2)))

حاصل کار ماتریس بی‌مقیاس‌شده‌ی زیر خواهد بود:

r-topsis

قدم سوم، تاثیر دادن اهمیت معیارها

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

طراحی قیمت وزن cpu شارژدهی اینترنت دوربین اندازه صفحه
۰٫۱ ۰٫۳ ۰٫۰۵ ۰٫۱ ۰٫۲ ۰٫۰۵ ۰٫۲

جدول بالا را در قالب یک بردار به نام w در R به وجود می‌آوریم:

w <- c(0.2,0.05,0.2,0.1,0.05,0.3,0.1)

قدم بعدی تاثیر دادن این بردار در ماتریس تصمیم‌گیری است. این عمل را با ضرب کردن عناصر هر ستون ماتریس با عنصر متناظر آن در بردار وزن‌ها انجام می‌دهیم و نتیجه‌ را در ماتریسی به نام v ذخیره می‌کنیم:

v <- t(w * t(r))
> v
       screen         MP    charge        cpu     weight     price     design
g5  0.1139127 0.03123475 0.1026105 0.06195856 0.02722842 0.1595457 0.06195856
v10 0.1225098 0.03123475 0.1294471 0.04818999 0.03287960 0.1861811 0.04818999
s7  0.1096141 0.02342606 0.1127588 0.06195856 0.02602969 0.1728634 0.06195856
>

خط اول کد بالا این کار را برای ما انجام می‌دهد. بردار وزن‌ها در نتیجه نهایی تاثیرگذار خواهد بود.

قدم چهارم، تعیین ایده‌آل مثبت و منفی

تا اینجا یک ماتریس به نام v داریم که آن را بی‌مقیاس کرده‌ایم و وزن‌های مورد نظر ما روی آن اعمال شده است، حالا نوبت تعیین ایده‌آل‌های مثبت و منفی است. این ایده‌آل‌ها دو گزینه‌ی فرضی هستند که به ترتیب بهترین و بدترین مقادیر معیارها را دارند، به زبان ساده در هر ستون ماتریس v بهترین عدد را درنظر می‌گیریم، این اعداد گزینه‌ی فرضی ایده‌آل مثبت هستند و اگر بدترین عددها را انتخاب کنیم گزینه‌ی ایده‌ال منفی را خواهیم داشت.

در جدول اولیه‌ی ما معیارها به دو گروه مثبت و منفی تقسیم شده بودند،(وزن و قیمت معیارهایی منفی بودند). گزینه‌ی ایده‌آل در این معیارهای منفی کمترین مقدار را دارد، به همین دلیل هنگام نوشتن دستوری که قرار است در معیارهای منفی بهترین عدد را مشخص کند باید حواسمان باشد که برخلاف معیارهای مثبت، کوچکترین عدد را انتخاب کند. ساده‌ترین روش استفاده از شرط یا دستور if است اما در R به دلیل پشتیبانی از بردار و ماتریس، در این مورد و بسیاری از موارد دیگر نیازی به تعریف شرط نخواهیم داشت، کافیست به نحوی ستون‌های متناظر با معیارهای منفی را در یک ۱- ضرب کنیم تا عدد موردنظر همانند معیارهای مثبت همان بزرگترین عدد باشد.  یک بردار مشخصه‌کننده معیارهای مثبت و منفی تعریف می‌کنیم و همانند بردار وزن آن را در ماتریس v ضرب می‌کنیم:

> i <- c(1,1,1,1,-1,-1,1)
> vm <- t(i * t(v))
> vm
       screen         MP    charge        cpu      weight      price     design
g5  0.1139127 0.03123475 0.1026105 0.06195856 -0.02722842 -0.1595457 0.06195856
v10 0.1225098 0.03123475 0.1294471 0.04818999 -0.03287960 -0.1861811 0.04818999
s7  0.1096141 0.02342606 0.1127588 0.06195856 -0.02602969 -0.1728634 0.06195856

همانطور که می‌بینید دو ستونی که شامل معیارهای منفی ما می‌شد خود منفی شدند، حالا فقط کافی است گزینه‌های ایده‌آل مثبت و منفی را مشخص کنیم و در دوبردار به نام‌های AP‌ و AN ذخیره کنیم:

> ap <- (apply(vm,MARGIN = 2,FUN = max)) * i
> ap
    screen         MP     charge        cpu     weight      price     design 
0.12250984 0.03123475 0.12944708 0.06195856 0.02602969 0.15954574 0.06195856 
> an <- (apply(vm,MARGIN = 2,FUN = min)) * i
> an
    screen         MP     charge        cpu     weight      price     design 
0.10961407 0.02342606 0.10261049 0.04818999 0.03287960 0.18618109 0.04818999

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

قدم پنجم، محسابه‌ی فاصله‌ی هر گزینه از گزینه‌های ایده‌آل مثبت و منفی

در این مرحله فاصله‌ی اقلیدسی هر گزینه(در واقع ردیف‌های ماتریس v) را از گزینه‌های مثبت و منفی محاسبه می‌کنیم و در دو بردار  dp و dn ذخیره می‌کنیم. فرمول فاصله همان فرمول فاصله‌ی دو نقطه در فضا در ریاضی دبیرستان است، و با تابع apply که در مرحله قبلی استفاده کردیم به راحتی می‌توان محاسبات لازم را بدون نوشتن حلقه انجام داد:

> dp <- apply(v,1,function(x)sqrt(sum((x-ap)^2)))
> dp
        g5        v10         s7 
0.02820551 0.03369733 0.02613688 
> dn <- apply(v,1,function(x)sqrt(sum((x-an)^2)))
> dn
        g5        v10         s7 
0.03464070 0.03078115 0.02657850

قدم آخر، محاسبه‌ی شاخص تصمیم‌گیری

آخرین مرحله محاسبه‌ی شاخص c برای هر گزینه با فرمول c=dn/dp+dn است، همین فرمول را عینا در R می‌نویسیم، گزینه‌ای که بیشترین c را داشت گزینه‌ی برتر است:

> c <- dn / (dp + dn)
> sort(c,decreasing =TRUE)
       g5        s7       v10 
0.5511979 0.5041887 0.4773864

دستور sort عناصر بردار شما را بر اساس اندازه مرتب می‌کند، همانطور که می‌بینید گزینه‌ی G5 در اینجا بیشترین مقدار c را دارد و بهترین گزینه است.

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



برچسب ها : ,