- فعال کردن خاصیت Contained Databases
قبل از استفاده از Contained Databases می بایست این امکان را فعال کرد. برای این کار میتوانید از SQL Server Management Studio یا T-SQL commands استفاده نمایید. بر روی نام Instance راست کلیت کنید و گزینه Properties را انتخاب نمایید. از گزینه Advanced که در شکل زیر مشاهده مینمایید خاصیت Enable Contained Databases را بر روی True قرار دهید.
یا میتوایند از sp_configure این کار را انجام دهید.دستورات زیر این موضوع را نشان میدهد.
sp_configure 'show advanced options',1 GO RECONFIGURE WITH OVERRIDE GO sp_configure 'contained database authentication',1 GO RECONFIGURE WITH OVERRIDE GO
- ایجاد یا تغییر یک پایگاه داده از نوع Contained Databases
برای ایجاد یک پایگاه داده با این خاصیت یا تغییر پایگاه داده موجود کافیست مقدار گزینه Containment type را بر روی Partial قرار دهید. برای پایگاه داده موجود از پنجره Properties پایگاه داده صفحه Options را انتخاب کنید.
- ایجاد یک کاربر برای پایگاه داده Contained Databases
برای تعریف یک کاربر در سطح پایگاه داده پوشه Security پایگاه داده خود را باز کنید بر روی پوشه Users راست کیلک و گزینه New User را انتخاب نمایید از گزینه User type که در شکل زیر نشان داده شده است SQL user with password را انتخاب نمایید و نام کاربر و رمز عبور و تکرار آن را وارد نمایید. کاربر ایجاد شده در سطح پایگاه داده میباشد و با انتقال به سرور دیگر نیر قابل دسترسی میباشد.
- اتصال به پایگاه داده Contained Databases
برای اتصال به پایگاه داده کافیست در حالت SQL Server Authentication نام کاربری و رمز عبور جدید را وارد و گزینه Options را انتخاب و از برگه Additional Connection Parameters نام پایگاه داده مورد نظر را مانند شکل زیر وارد نمایید پس از ورود تنها پایگاه داده خود را مشاهده مینمایید. یکی از کاربرهای این قابلیت برای مدیران سرور پایگاه داده میباشد که بدون استفاده از مجوز sysadmin به کاربران اجازه دسترسی را میدهد.
در این قسمت بر روی توابع Topcount, bottomcount , toppercent, bottompercent, topsum, bottomsum تمرکز خواهیم داشت.
در ابتدا تصور کنید بخواهیم میزان فروش اینترنتی را برای پنج ردیف از دسته بندیهای محصولات واکشی کنیم.
Select [Measures].[Internet Sales Amount] on columns, non empty( topcount([Product].[Product Categories].[Subcategory],5) ) on rows From [Adventure Works]
در تابع بالا پنج ردیف ابتدایی (به صورت فیزیکی) برگردانده میشوند.
در اینجا تابع topcount دارای دو پارامتر می باشد که پارامتر دوم آن مشخص کنندهی تعداد ردیف واکشی شده و پارامتر اول آن، مشخص کنندهی دایمنشنی میباشد که عمل واکشی برای آن صورت میگیرد. همچنین در بالا از تابع Non empty برای حذف ردیفهای دارای مقدار Null استفاده شده است. حال تصور کنید بخواهیم پنج دسته بندی محصولی را دریافت کنیم که دارای بیشترین میزان فروش اینترنتی میباشند.
Select [Measures].[Internet Sales Amount] on columns, non empty( topcount( [Product].[Product Categories].[Subcategory], 5, [Measures].[Internet Sales Amount] ) ) on rows From [Adventure Works]
خروجی بر اساس میزان فروش اینترنتی به صورت نزولی مرتب شده است.
تابع Topcount به عنوان پارامتر سوم میتواند نام یک Measure را دریافت کند و خروجی را براساس آن شاخص، برگرداند. امکان واکشی و مرتب سازی در تابع Topcount
برای یک شاخص متفاوت از شاخص واکشی شده در یک محور دیگر نیز وجود دارد به مثال زیر دقت کنید:
Select [Measures].[Internet Sales Amount] on columns, topcount( [Product].[Product Categories].[Subcategory], 5, [Measures].[Reseller Sales Amount] ) on rows From [Adventure Works]
همانطور که مشخص میباشد، پنج دسته بندی محصولاتی که دارای بیشترین میزان فروش نمایندگان فروش میباشند، در خروجی واکشی شدهاند؛ در حالیکه در محور ستون میزان فروش اینترنتی واکشی شده است.
برای درک بیشتر همین کوئری را دوباره بازنویسی کرده اما اینبار در محور ستون هر دو شاخص [Measures].[Internet Sales Amount],[Measures].[Reseller Sales Amount] را واکشی میکنیم.
Select {[Measures].[Internet Sales Amount],[Measures].[Reseller Sales Amount]} on columns, topcount( [Product].[Product Categories].[Subcategory], 5, [Measures].[Reseller Sales Amount] ) on rows From [Adventure Works]
با بررسی خروجی دو کوئری بالا تفاوت واکشی را متوجه خواهید شد. در هر دو کوئری واکشی براساس شاخص [Measures].[Reseller Sales Amount] انجام شده است
اما واکشی در محور ستون متفاوت میباشد. (دقیقا مانند T/SQL که میتوانستیم، مرتب سازی براساس فیلدی باشد که در قسمت Projection حاضر نبوده و در این حالت در برخی موارد ظاهرا خروجی مرتب نمیباشد)
حال تصور کنید بخواهیم 30 دسته بندی محصولاتی را داشته باشیم که دارای کمترین میزان فروش اینترنتی میباشند. برای این منظور از تابع bottomcount استفاده میکنیم
Select [Measures].[Internet Sales Amount] on columns, bottomcount( [Product].[Product Categories].[Subcategory], 30, [Measures].[Internet Sales Amount] ) on rows From [Adventure Works]
ردیف هایی که دارای مقدار Null می باشند هم در خروجی قرار می گیرند
Select [Measures].[Internet Sales Amount] on columns, non empty bottomcount( [Product].[Product Categories].[Subcategory], 30, [Measures].[Internet Sales Amount] )on rows From [Adventure Works]
در مثال بالا ردیفهای دارای مقدار Null را از خروجی حذف کرده ایم.
گاهی نیاز میباشد که تعداد دسته بندیهای محصولاتی را واکشی کنیم که دارای بیشترین یا کمترین میزان فروش اینترنتی میباشند و سرجمع فروش اینترنتی آنها بیشتر یا کمتر از X درصد از فروش اینترنتی کل میباشد را داشته باشند. به عنوان مثال میخواهیم ببینیم کدام دسته بندی محصولات شامل بیشترین میزان فروش اینترنتی میباشند و سرجمع فروش آنها 53 در صد از کل فروش اینترنتی میباشند.
Select [Measures].[Internet Sales Amount] on columns, { toppercent( [Product].[Product Categories].[Subcategory], 53, [Measures].[Internet Sales Amount] ), [Product].[Product Categories] } on rows From [Adventure Works]
و یا واکشی دسته محصولاتی که دارای کمترین میزان فروش اینترنتی میباشند و سرجمع فروش اینترنتی آنها کمتر از 1 درصد کل میزان فروش اینترنتی میباشد.
Select [Measures].[Internet Sales Amount] on columns, non empty bottompercent( [Product].[Product Categories].[Subcategory], --0.01, 1, [Measures].[Internet Sales Amount] ) on rows From [Adventure Works]
کاربرد تابع Topsum در کوئری زیر نمایش داده شده است
Select [Measures].[Internet Sales Amount] on columns, topsum( [Product].[Product Categories].[Subcategory], 25000000, [Measures].[Internet Sales Amount] ) on rows From [Adventure Works]
در این کوئری از تابع TopSum استفاده شده است که عملا حداکثر تعداد دسته بندی محصولاتی را بازیابی میکند که دارای بیشترین میزان فروش بوده اند و همچنین در مجموع بیش از 25000000 فروش داشته باشند .
تابع bottomsum عملا تعداد دسته بندی محصولاتی را که دارای کمترین میزان فروش بوده اند و همچنین سرجمع میزان فروش اینترنتی آنها 100000 بوده است را بر می گرداند. البته خروجی توسط non empty ، فیلتر شده است و خروجی هایی که کاملا Null می باشند، حذف گردیده اند.
Select [Measures].[Internet Sales Amount] on columns, non empty bottomsum( [Product].[Product Categories].[Subcategory], 100000, [Measures].[Internet Sales Amount] )on rows From [Adventure Works]
آشنایی با Leaflet
<script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script> <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" />
#map { height: 600px; }
var map = L.map('map').setView([29.6760859,52.4950737], 13);
var osmUrl='http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; var osmAttrib='Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors'; var osm = new L.TileLayer(osmUrl, { maxZoom: 18, attribution: osmAttrib}).addTo(map);
Marker، دایره و چندضلعی
در کنار نمایش Tileها میتوان اشکال گرافیکی نیز به نقشه اضافه کرد؛ مثل مارکر(نقطه)، مستطیل، دایره و یا یک Popup. اضافه کردن یک Marker به سادگی، با کد زیر صورت میپذیرد:
var marker = L.marker([29.623116,52.497856]).addTo(map);
محل مورد نظر به شیء مارکر پاس داده شده و مقدار بازگشتی به map اضافه شده است.
نمایش چند ضلعی و دایره هم کار ساده ای است. برای دایره باید ابتدا مختصات مرکز دایره و شعاع به متر را به L.circle پاس داد:
var circle = L.circle([29.6308217,52.5048021], 500, { color: 'red', fillColor: '#f03', fillOpacity: 0.5 }).addTo(map);
در کد بالا علاوه بر محل و اندازه دایره، رنگ محیط، رنگ داخل و شفافیت (opacity) نیز مشخص شدهاند.
برای چند ضلعیها میتوان به این صورت عمل کرد:
var polygon = L.polygon([ [29.628453, 52.488838], [29.637368, 52.493987], [29.637168, 52.503987] ]).addTo(map);
کار کردن با Popup ها
از Popup میتوان برای نمایش اطلاعات اضافهای بر روی یک محل خاص یا یک عنوان به مانند Marker استفاده کرد. برای مثال میتوان اطلاعاتی دربارهی محل یک Marker یا دایره نمایش داد. در هنگام ایجاد marker، دایره و چندضلعی مقادیر بازگشتی در متغیرهای جدایی ذخیره شدند. اکنون میتوان به آن اشیاء یک popup اضافه کرد:
marker.bindPopup("باغ عفیف آباد").openPopup(); circle.bindPopup("I am a circle."); polygon.bindPopup("I am a polygon.");
به علت اینکه openPopup برای Marker صدا زده شده، به صورت پیشفرض popup را نمایش میدهد. اما برای بقیه، نمایش با کلیک خواهد بود. البته الزاما نیازی نیست که popup روی یک شیء نمایش داده شود، میتوان popupهای مستقلی نیز ایجاد کرد:
var popup = L.popup() .setLatLng([51.5, -0.09]) .setContent("I am a standalone popup.") .openOn(map);
اشیاء تغییر ناپذیر برای دادههای استاتیک استفاده میشوند و نمونههایی از آن در بخش زیر لیست شدهاند:
چگونه میتوان در سی شارپ اشیاء تغییر ناپذیر را ایجاد کنیم؟
اشیاء تغییر ناپذیر (immutable objects) تنها توسط کلاسهای تغییر ناپذیر (immutable classes) میتوانند ایجاد شوند.
برای ایجاد کلاسی تغییر ناپذیر، سه مرحله باید طی شود:
1- حذف بلاک Set: همانطور که گفته شد، بخش Set از property ها باید حذف شود. با حذف این بخش بعد از بارگزاری شیء در حافظه، دیگر نمیتوان آن را تغییر داد:
public class Currency { private string _currencyName; private string _countryName; public string CurrencyName { get { return _currencyName; } } public string CountryName { get { return _countryName; } } }
2- مهیا کردن پارامترها از طریق سازندهی کلاس: با حذف بلاک set، راهی برای بارگزاری اطلاعات، در کلاس وجود ندارد. از این رو میتوان از طریق پارامترهای سازندهی کلاس، اطلاعات را به شیء ارسال کرد.
private string _currencyName; private string _countryName; public Currency(string paramCurrencyName,string paramCountryName) { _currencyName= paramCurrencyName; _countryName = paramCountryName; }
3- تعریف متغیرهای کلاس به صورت فقط خواندنی READONLY
در تعریف اولیه گفته شد که اشیاء immutable نه از طریق خارجی (کاربر) و «کمی فراتر» نه از طریق داخلی (اعضای کلاس) قابل تغییر نیستند. اما کلاس ایجاد شده را میتوان بعد از ایجاد نمونهای از آن، مجددا تغییر داد. کافی است یک متد به شکل زیر در آن تعریف کنیم و بهراحتی وضعیت شیء را از طریق آن تغییر دهیم.
public void DoSomthing() { _countryName = "somthing else"; }
public class Currency { private readonly string _currencyName; private readonly string _countryName; public string CurrencyName { get { return _currencyName; } } public string CountryName { get { return _countryName; } } public Currency(string paramCurrencyName,string paramCountryName) { _currencyName= paramCurrencyName; _countryName = paramCountryName; } }
Blazor 5x
مبانی Blazor
- قسمت 4 : بخش 1 - Data Binding
- قسمت 5 : بخش 2 - کامپوننتها
- قسمت 6 : بخش 3 - چرخههای حیات کامپوننتها
- قسمت 7 : بخش 4 - انتقال اطلاعات از کامپوننتهای فرزند به کامپوننت والد
- قسمت 8 : بخش 5 - تامین محتوای نمایشی کامپوننتهای فرزند توسط کامپوننت والد
- قسمت 9 : بخش 6 - ساده سازی تعاریف ویژگیهای المانها و انتقال پارامترها به چندین زیر سطح
- قسمت 10 : بخش 7 - مسیریابی
- قسمت 11 : بخش 8 - کار با جاوا اسکریپت
- قسمت 12 : بخش 9 - یک تمرین
کار با فرمها
- قسمت 13 : بخش 1 - کار با EF Core در برنامههای Blazor Server
- قسمت 14 : بخش 2 - تعریف فرمها و اعتبارسنجی آنها
- قسمت 15 : بخش 3 - ویرایش اطلاعات
- قسمت 16 : بخش 4 - تهیه سرویسهای آپلود تصاویر
- قسمت 17 : بخش 5 - آپلود تصاویر
- قسمت 18 : بخش 6 - حذف اطلاعات
- قسمت 19 : بخش 7 - نکات ویژهی کار با EF-Core در برنامههای Blazor Server
- قسمت 20 : بخش 8 - استفاده از یک کامپوننت ثالث HTML Editor
- قسمت 21 : بخش 1 - افزودن قالب ابتدایی Identity
- قسمت 22 : بخش 2 - ورود به سیستم و خروج از آن
- قسمت 23 : بخش 3 - کار با نقشهای کاربران
- قسمت 26 : ایجاد و تنظیمات اولیه
- قسمت 27 : کار با سرویسهای Web API
- قسمت 28 : نمایش لیست اطلاعات دریافتی از Web API
- قسمت 29 : یک تمرین: رزرو کردن یک اتاق انتخابی
- قسمت 30 : افزودن پرداخت آنلاین توسط درگاه مجازی پرباد
- قسمت 31 : بخش 1 - انجام تنظیمات اولیه
- قسمت 32 : بخش 2 - ثبت نام، ورود به سیستم و خروج از آن
- قسمت 33 : بخش 3 - بهبود تجربهی کاربری عدم دسترسیها
- پیاده سازی سیاستهای دسترسی پویای سمت سرور و کلاینت در برنامههای Blazor WASM
- قسمت اول : معرفی SSR
- قسمت دوم : بررسی حالت رندر سمت سرور
- قسمت سوم : روش ارتقاء برنامههای Blazor Server قدیمی به دات نت 8
- قسمت چهارم : معرفی فرمهای جدید تعاملی
- قسمت پنجم : امکان تعریف جزیرههای تعاملی Blazor Server
- قسمت ششم : نکات تکمیلی ویژگی راهبری بهبود یافتهی صفحات SSR
- قسمت هفتم : امکان تعریف جزیرههای تعاملی Blazor WASM
- قسمت هشتم : مدیریت انتقال اطلاعات Pre-Rendering سمت سرور، به جزایر تعاملی
- قسمت نهم : معرفی حالت رندر تعاملی خودکار
- قسمت دهم : مدیریت حالت کاربران در روشهای مختلف رندر
- قسمت یازدهم : قالب جدید پیاده سازی اعتبارسنجی و احراز هویت - بخش اول
- قسمت دوازدهم : قالب جدید پیاده سازی اعتبارسنجی و احراز هویت - بخش دوم
- قسمت سیزدهم : امکان تعریف Sections
- قسمت چهاردهم : امکان استفاده از کامپوننتهای Blazor در برنامههای ASP.NET Core 8x
- Best practiceهای یک پروژه Blazor
- کامپوننتهای جنریک در Blazor
- مدیریت حالت در برنامههای Blazor توسط الگوی Observer - قسمت اول
- مدیریت حالت در برنامههای Blazor توسط الگوی Observer - قسمت دوم
- روش آپلود فایلها به همراه اطلاعات یک مدل در برنامههای Blazor WASM 5x
- دریافت و نمایش فایلهای PDF در برنامههای Blazor WASM
- ارسال خطاهای رخدادهی در برنامههای سمت کلاینت Blazor WASM، به تلگرام
- بهبود کارآیی نمایش لیستها در Blazor با استفاده از دایرکتیو key@
- معرفی Blazor Hybrid
- امکان استفاده از کتابخانههای native در Blazor WASM 6x
- امکان ساخت برنامههای دسکتاپ چندسکویی Blazor در دات نت 6
- حل مشکل بارگذاری اولیه دستورات جاوا اسکریپتی در پروژههای Blazor
- پیاده سازی Remote Validation در Blazor
- روش ایجاد پروژههای کتابخانهای کامپوننتهای Blazor
- استفاده از date picker شمسی جاوا اسکریپتی در Blazor با قابلیت ورود تاریخ به صورت دستی
- ارائهی قالبی عمومی برای استفاده از تقویمهای جاوااسکریپتی در Blazor
- بهبود صفحهی بارگذاری اولیه در Blazor WASM
- استفاده از چند دکمه با عملکردهای مختلف برای ارسال یک EditForm در Blazor
- دستیابی به HttpContext در Blazor Server
- جلوگیری از دوباره اجرا شدن ناخواستهی متدهای نامتقارن در Blazor
- نکات ویژه کار با عملیات نامتقارن در Blazor Server
- استفاده از لنگر (anchor) برای اسکرول به قسمت خاصی از صفحه در Blazor Server
دوره داده کاوی
UI-Router ابزاری برای مسیریابی در AngularJS است که این امکان را برایتان فراهم میکند تا بخشهای برنامه رابط کاربریتان را به شکل یک ماشین حالت ساماندهی کنید. برخلاف سرویس route$ که بر اساس مسیریابی URLها ساماندهی شده و کار میکند، UI-Router بر اساس حالتها کار میکند، که این حالتها میتوانند در صورت لزوم مسیریابی هم داشته باشند.
UI-Router یکی از افزونههای مجموعه Angular-ui، و پاراگراف بالا معرفی آن در صفحه خانگیش است (تقریبا!). این افزونه جزئیات مفصلی دارد و در این مطلب تنها به معرفی آن خواهم پرداخت (بر اساس مطالب صفحه خانگیش). پیش از ادامه پیشنهاد میکنم اگر مطالب زیر را نخواندهاید ابتدا آنها را مرور کنید:
برای استفاده از UI-Router باید:
- فایل جاوا اسکریپت آن را دانلود کنید (released یا minified).
- در صفحه اصلی برنامهتان پس از include کردن فایل اصلی AngularJS فایل angular-ui-router.js (یا angular-ui-router.min.js) را include کنید.
- 'ui.router' را به لیست وابستگیهای ماژول اصلی اضافه کنید.
<!doctype html> <html ng-app="myApp"> <head> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.min.js"></script> <script src="js/angular-ui-router.min.js"></script> <script> var myApp = angular.module('myApp', ['ui.router']); // For Component users, it should look like this: // var myApp = angular.module('myApp', [require('angular-ui-router')]); </script> ... </head> <body> ... </body> </html>
حالتها و viewهای تو در تو
قابلیت اصلی UI-Router امکان تعریف حالتها و vieweهای تو در تو است. در مطلب مسیریابی در AngularJs #بخش اول دایرکتیو ng-view معرفی شده است. هنگام استفاده از سرویس route$ با این دایرکتیو میتوان محل مورد نظر برای بارگذاری محتویات مربوط به مسیرها را مشخص کرد. دایرکتیو ui-view در UI-Router همین نقش را دارد. فرض کنید این کد فایل index.html باشد:<!-- index.html --> <body> <div ui-view></div> <!-- We'll also add some navigation: --> <a ui-sref="state1">State 1</a> <a ui-sref="state2">State 2</a> </body>
در ادامه برای هر کدام از حالتها یک template اضافه میکنیم:
فایل state1.html:
<!-- partials/state1.html --> <h1>State 1</h1> <hr/> <a ui-sref="state1.list">Show List</a> <div ui-view></div>
<!-- partials/state2.html --> <h1>State 2</h1> <hr /> <a ui-sref="state2.list">Show List</a> <div ui-view></div>
دو نکته قابل توجه در این templateها وجود دارد. اول اینکه همانطور که میبینید templateها خود شامل تگی با دایرکتیو ui-view هستند. و دوم مقدار دایرکتیو ui-sref است که به صورت state1.list و state2.list آمده است. این جدا سازی با نقطه نشان دهنده سلسله مراتب حالتهاست. یعنی حالتهای state1 و state2 هرکدام حالت فرزندی به نام list دارند. در ادامه وقتی حالتها و مسیریابی را در ()app.config تعریف کنیم این مسائل از هالهای از ابهام که در آن هستند خارج میشوند! فعلا بیاید با راهنمای UI-Router پیش برویم و فایلهای template حالتهای فرزند را تعریف کنیم. templateهایی که قرار است در ui-view پدرانشان بارگذاری شوند:
<!-- partials/state1.list.html --> <h3>List of State 1 Items</h3> <ul> <li ng-repeat="item in items">{{ item }}</li> </ul>
<!-- partials/state2.list.html --> <h3>List of State 2 Things</h3> <ul> <li ng-repeat="thing in things">{{ thing }}</li> </ul>
myApp.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) { // // For any unmatched url, redirect to /state1 $urlRouterProvider.otherwise("/state1"); // // Now set up the states $stateProvider .state('state1', { url: "/state1", templateUrl: "partials/state1.html" }) .state('state1.list', { url: "/list", templateUrl: "partials/state1.list.html", controller: function($scope) { $scope.items = ["A", "List", "Of", "Items"]; } }) .state('state2', { url: "/state2", templateUrl: "partials/state2.html" }) .state('state2.list', { url: "/list", templateUrl: "partials/state2.list.html", controller: function($scope) { $scope.things = ["A", "Set", "Of", "Things"]; } }) }]);
خصوصیت url مشخص کننده مسیر حالت است. این خصوصیت همان مقداریست که به عنوان پارامتر اول به ()routeProvider.when$ پاس میشد. در این پارامتر میشود متغیرهای url را هم به همان ترتیب تعریف کرد. مثلا اگر حالت state1 در آدرسش یک پارامتر id داشته باشد میشود آن را به این ترتیب تعریف کرد:
.state('state1', { url: "/state1/:id", templateUrl: "partials/state1.html" })
$stateParams.id
.state('list', { parent: "state1", url: "/list", templateUrl: "partials/state1.list.html", controller: function($scope) { $scope.items = ["A", "List", "Of", "Items"]; } }) .state('list', { parent: "state2", url: "/list", templateUrl: "partials/state2.list.html", controller: function($scope) { $scope.items = ["A", "List", "Of", "Items"]; } })
- وابستگیهای فراهم شده در حالت پدر به وسیله "resolve"
- دادههای سفارشی مشخص شده در خصوصیت data حالت پدر
.state('state1', { url: "/state1", templateUrl: "partials/state1.html", data:{ foodata: 'addorder' } })
$state.current.data.foodata
Viewهای نامگذاری شده و چندگانه
<!-- index.html --> <body> <div ui-view="viewA"></div> <div ui-view="viewB"></div> <!-- Also a way to navigate --> <a ui-sref="route1">Route 1</a> <a ui-sref="route2">Route 2</a> </body>
myApp.config(function ($stateProvider) { $stateProvider .state('index', { url: "", views: { "viewA": { template: "index.viewA" }, "viewB": { template: "index.viewB" } } }) .state('route1', { url: "/route1", views: { "viewA": { template: "route1.viewA" }, "viewB": { template: "route1.viewB" } } }) .state('route2', { url: "/route2", views: { "viewA": { template: "route2.viewA" }, "viewB": { template: "route2.viewB" } } }) });
چند نکته
.state('list', { parent: "state1", url: "/list", templateUrl: "partials/state1.list.html", controller: "state1ListController as listCtrl1" } }) .state('list', { parent: "state2", url: "/list", templateUrl: "partials/state2.list.html", controller: "state2ListController as listCtrl2" } })
حالتهای انتزاعی
حساسیت به حروف بزرگ و کوچک
- در فایل "angular-ui-router.js" عبارت "new RegExp(compiled)" را پیدا کرده و آن را به "RegExp(compiled, 'i')" تبدیل کنید. و یا در "angular-ui-router.min.js" (هرکدام از فایلها که استفاده میکنید) عبارت new RegExp(o) را پیدا کرده و آن را به new RegExp(o, "i") تبدیل کنید. همین؛ صدایش را هم در نیاورید!
مروری بر روش ها و رویکردهای مختلف در یادگیری مدل
همان گونه که اشاره شد در روشهای با ناظر (برای مثال الگوریتمهای دسته بندی) کل مجموعه دادهها به دو بخش مجموعه دادههای آموزشی و مجموعه دادههای آزمایشی تقسیم میشود. در مرحله یادگیری (آموزش) مدل، الگوریتم براساس مجموعه دادههای آموزشی یک مدل میسازد که شکل مدل ساخته شده به الگوریتم یادگیرنده مورد استفاده بستگی دارد. در مرحله ارزیابی براساس مجموعه دادههای آزمایشی دقت و کارائی مدل ساخته شده بررسی میشود. توجه داشته باشید که مجموعه دادههای آزمایشی برای مدل ساخته شده پیش از این ناشناخته هستند.
در مرحله یادگیری مدل؛ برای مقابله با مشکل به خاطرسپاری (Memorization) مجموعه دادههای آموزشی، در برخی موارد بخشی از مجموعه دادههای آموزشی را از آن مجموعه جدا میکنند که با عنوان مجموعه داده ارزیابی (Valid Dataset) شناسائی میشود. استفاده از مجموعه داده ارزیابی باعث میشود که مدل ساخته شده، مجموعه دادههای آموزشی را حقیقتاً یاد بگیرد و در پی به خاطرسپاری و حفظ آن نباشد. به بیان دیگر در مرحله یادگیری مدل؛ تا قبل از رسیدن به لحظه ای، مدل در حال یادگیری و کلی سازی (Generalization) است و از آن لحظه به بعد در حال به خاطرسپاری (Over Fitting) مجموعه دادههای آموزشی است. بدیهی است به خاطرسپاری باعث افزایش دقت مدل برای مجموعه دادههای آموزشی و بطور مشابه باعث کاهش دقت مدل برای مجموعه دادههای آزمایشی میشود. بدین منظور جهت جلوگیری از مشکل به خاطرسپاری از مجموعه داده ارزیابی استفاده میشود که به شکل غیر مستقیم در فرآیند یادگیری مدل، وارد عمل میشوند. بدین ترتیب مدلی که مفهومی را از دادههای آموزشی فرا گرفته، نسبت به مدلی که صرفاً دادههای آموزشی را به خوبی حفظ کرده است، برای مجموعه داده آزمایشی دقت به مراتب بالاتری دارد. این حقیقت در بیشتر فرآیندهای آموزشی که از مجموعه داده ارزیابی بهره میگیرند قابل مشاهده است.
در روشهای بدون ناظر یا روشهای توصیفی (برای مثال خوشه بندی) الگوریتمها فاقد مراحل آموزشی و آزمایشی هستند و در پایان عملیات یادگیری مدل، مدل ساخته شده به همراه کارائی آن به عنوان خروجی ارائه میشود، برای مثال در الگوریتمهای خوشه بندی خروجی همان خوشههای ایجاد شده هستند و یا خروجی در روش کشف قوانین انجمنی عبارت است از مجموعه ای از قوانین «اگر- آنگاه» که بیانگر ارتباط میان رخداد توامان مجموعه ای از اشیاء با یکدیگر میباشد.
در این قسمت عملیات ساخت مدل در فرآیند داده کاوی برای سه روش دسته بندی، خوشه بندی و کشف قوانین انجمنی ارائه میشود. بدیهی است برای هر کدام از این روشها علاوه بر الگوریتمهای معرفی شده، الگوریتمهای متنوعی دیگری نیز وجود دارد. در ادامه سعی میشود به صورت کلان به فلسفه یادگیری مدل پرداخته شود. فهرست مطالب به شرح زیر است:
1- دسته بندی:
1-1- دسته بندی مبتنی بر درخت تصمیم (Decision Tree based methods) :
1-2- دسته بندهای مبتنی بر قانون (Rule based methods) :
1-3- دسته بندهای مبتنی بر نظریه بیز (Naïve Bayes and Bayesian belief networks) :
2- خوشه بندی:
2-1- خوشه بندی افرازی (Centroid Based Clustering) :
2-1-1- الگوریتم خوشه بندی K-Means :
2-1-2- الگوریتم خوشه بندی K-Medoids :
2-1-3- الگوریتم خوشه بندی Bisecting K-Means :
2-1-4- الگوریتم خوشه بندی Fuzzy C-Means :
2-2- خوشه بندی سلسله مراتبی (Connectivity Based Clustering (Hierarchical Clustering :
2-2-1- روشهای خوشه بندی تجمیعی (Agglomerative Clustering) :
2-2-2- روشهای خوشه بندی تقسیمی (Divisive Clustering) :
2-3- خوشه بندی مبتنی بر چگالی (Density Based Clustering) :
3- کشف قوانین انجمنی :
3-1- الگوریتم های Apriori ، Brute-Force و FP-Growth:
1- دسته بندی:
در الگوریتمهای دسته بندی، برای هر یک از رکوردهای مجموعه داده مورد کاوش، یک برچسب که بیانگر حقیقتی از مساله است تعریف میشود و هدف الگوریتم یادگیری؛ یافتن نظم حاکم بر این برچسب هاست. به بیان دیگر در مرحله آموزش؛ مجموعه دادههای آموزشی به یکی از الگوریتمهای دسته بندی داده میشود تا بر اساس سایر ویژگیها برای مقادیر ویژگی دسته، مدل ساخته شود. سپس در مرحله ارزیابی؛ دقت مدل ساخته شده به کمک مجموعه دادههای آزمایشی ارزیابی خواهد شد. انواع گوناگون الگوریتمهای دسته بندی را میتوان بصورت ذیل برشمرد:
1-1- دسته بندی مبتنی بر درخت تصمیم (Decision Tree based methods):
از مشهورترین روشهای ساخت مدل دسته بندی میباشد که دانش خروجی را به صورت یک درخت از حالات مختلف مقادیر ویژگیها ارائه میکند. بدین ترتیب دسته بندیهای مبتنی بر درخت تصمیم کاملاً قابل تفسیر میباشند. در حالت کلی درخت تصمیم بدست آمده برای یک مجموعه داده آموزشی؛ واحد و یکتا نیست. به بیان دیگر براساس یک مجموعه داده، درختهای تصمیم مختلفی میتوان بدست آورد. عموماً به منظور فراهم نمودن اطلاعات بیشتری از داده ها، از میان ویژگیهای موجود یک Case ابتدا آنهایی که دارای خاصیت جداکنندگی بیشتری هستند انتخاب میشوند. در واقع براساس مجموعه دادههای آموزشی از میان ویژگی ها، یک ویژگی انتخاب میشود و در ادامه مجموعه رکوردها براساس مقدار این ویژگی شکسته میشود و این فرآیند ادامه مییابد تا درخت کلی ساخته شود. پس از ساخته شدن مدل، میتوان آن را بر روی مجموعه دادههای آزمایشی اعمال (Apply) نمود. منظور از اعمال کردن مدل، پیش بینی مقدار ویژگی یک دسته برای یک رکورد آزمایشی براساس مدل ساخته شده است. توجه شود هدف پیش بینی ویژگی دسته این رکورد، براساس درخت تصمیم موجود است.
بطور کلی الگوریتمهای تولید درخت تصمیم مختلفی از جمله SPRINT، SLIQ، C4.5، ID3، CART و HUNT وجود دارد. این الگوریتمها به لحاظ استفاده از روشهای مختلف جهت انتخاب ویژگی و شرط توقف در ساخت درخت با یکدیگر تفاوت دارند. عموماً الگوریتمهای درخت تصمیم برای شناسائی بهترین شکست، از یک مکانیزم حریصانه (Greedy) استفاده میکنند که براساس آن شکستی که توزیع دستهها در گرههای حاصل از آن همگن باشد، نسبت به سایر شکستها بهتر خواهد بود. منظور از همگن بودن گره این است که همه رکوردهای موجود در آن متعلق به یک دسته خاص باشند، بدین ترتیب آن گره به برگ تبدیل خواهد شد. بنابراین گره همگن گره ای است که کمترین میزان ناخالصی (Impurity) را دارد. به بیان دیگر هر چه توزیع دستهها در یک گره همگنتر باشد، آن گره ناخالصی کمتری خواهد داشت. سه روش مهم برای محاسبه ناخالصی گره وجود دارد که عبارتند از: ضریب GINI، روش Entropy و Classification Error.
از مزایای درخت تصمیم میتوان به توانایی کار با دادههای گسسته و پیوسته، سهولت در توصیف شرایط (با استفاده از منطق بولی) در درخت تصمیم، عدم نیاز به تابع تخمین توزیع، کشف روابط غیرمنتظره یا نامعلوم و ... اشاره نمود.
همچنین از معایب درخت تصمیم نسبت به دیگر روشهای داده کاوی میتوان این موارد را برشمرد: تولید درخت تصمیم گیری هزینه بالائی دارد، در صورت همپوشانی گرهها تعداد گرههای پایانی زیاد میشود، طراحی درخت تصمیم گیری بهینه دشوار است، احتمال تولید روابط نادرست وجود دارد و ... .
میتوان موارد استفاده از دسته بند درخت تصمیم نسبت به سایر دسته بندی کنندههای تک مرحله ای رایج را؛ حذف محاسبات غیر ضروری و انعطاف پذیری در انتخاب زیر مجموعههای مختلفی از صفات برشمرد. در نهایت از جمله مسائل مناسب برای یادگیری درخت تصمیم، میتوان به مسائلی که در آنها نمونهها به شکل جفتهای «صفت-مقدار» بازنمائی میشود و همچنین مسائلی که تابع هدف، مقادیر خروجی گسسته دارد اشاره نمود.
1-2- دسته بندهای مبتنی بر قانون (Rule based methods):
این دسته بندها دانش خروجی خود را به صورت یک مجموعه از قوانین «اگر-آنگاه» نشان میدهند. هر قانون یک بخش شرایط (LHS: Left Hand Side) و یک بخش نتیجه (RHS: Right Hand Side) دارد. بدیهی است اگر تمام شرایط مربوط به بخش مقدم یک قانون درباره یک رکورد خاص درست تعبیر شود، آن قانون آن رکورد را پوشش میدهد. دو معیار Accuracy و Coverage برای هر قانون قابل محاسبه است که هر چه میزان این دو معیار برای یک قانون بیشتر باشد، آن قانون؛ قانونی با ارزشتر محسوب میشود.
Coverage یک قانون، برابر با درصد رکوردهایی است که بخش شرایط قانون مورد نظر در مورد آنها صدق میکند و درست تعبیر میشود. بنابراین هر چه این مقدار بیشتر باشد آن قانون، قانونی کلیتر و عمومیتر میباشد.
Accuracy یک قانون بیان میکند که در میان رکوردهایی که بخش شرایط قانون در مورد آنها صدق میکند، چند درصد هر دو قسمت قانون مورد نظر در مورد آنها صحیح است.
چنانچه مجموعه همه رکوردها را در نظر بگیریم؛ مطلوبترین حالت این است که همواره یک رکورد توسط یک و تنها یک قانون پوشش داده شود، به بیان دیگر مجموعه قوانین نهایی به صورت جامع (Exhaustive Rules) و دو به دو ناسازگار (Mutually Exclusive Rules) باشند. جامع بودن به معنای این است که هر رکورد حداقل توسط یک قانون پوشش داده شود و معنای قوانین مستقل یا دو به دو ناسازگار بودن بدین معناست که هر رکورد حداکثر توسط یک قانون پوشش داده شود.
مجموعه قوانین و درخت تصمیم عیناً یک مجموعه دانش را نشان میدهند و تنها در شکل نمایش متفاوت از هم هستند. البته روشهای مبتنی بر قانون انعطاف پذیری و تفسیرپذیری بالاتری نسبت به روشهای مبتنی بر درخت دارند. همچنین اجباری در تعیین وضعیت هایی که در یک درخت تصمیم برای ترکیب مقادیر مختلف ویژگیها رخ میدهد ندارند و از این رو دانش خلاصهتری ارائه میدهند.
1-3- دسته بندهای مبتنی بر نظریه بیز (Naïve Bayes and Bayesian belief networks):
دسته بند مبتنی بر رابطه نظریه بیز (Naïve Bayes) از یک چهارچوب احتمالی برای حل مسائل دسته بندی استفاده میکند. براساس نظریه بیز رابطه I برقرار است:
هدف محاسبه دسته یک رکورد مفروض با مجموعه ویژگیهای (A1,A2,A3,…,An) میباشد. در واقع از بین دستههای موجود به دنبال پیدا کردن دسته ای هستیم که مقدار II را بیشینه کند. برای این منظور این احتمال را برای تمامی دستههای مذکور محاسبه نموده و دسته ای که مقدار این احتمال به ازای آن بیشینه شود را به عنوان دسته رکورد جدید در نظر میگیریم. ذکر این نکته ضروری است که بدانیم نحوه محاسبه برای ویژگیهای گسسته و پیوسته متفاوت میباشد.
2- خوشه بندی:
خوشه را مجموعه ای از دادهها که به هم شباهت دارند تعریف میکنند و هدف از انجام عملیات خوشه بندی فهم (Understanding) گروه رکوردهای مشابه در مجموعه دادهها و همچنین خلاصه سازی (Summarization) یا کاهش اندازهی مجموعه دادههای بزرگ میباشد. خوشه بندی از جمله روش هایی است که در آن هیچ گونه برچسبی برای رکوردها در نظر گرفته نمیشود و رکوردها تنها براساس معیار شباهتی که معرفی شده است، به مجموعه ای از خوشهها گروه بندی میشوند. عدم استفاده از برچسب موجب میشود الگوریتمهای خوشه بندی جزء روشهای بدون ناظر محسوب شوند و همانگونه که پیشتر ذکر آن رفت در خوشه بندی تلاش میشود تا دادهها به خوشه هایی تقسیم شوند که شباهت بین داده ای درون هر خوشه بیشینه و بطور مشابه شباهت بین دادهها در خوشههای متفاوت کمینه شود.
چنانچه بخواهیم خوشه بندی و دسته بندی را مقایسه کنیم، میتوان بیان نمود که در دسته بندی هر داده به یک دسته (طبقه) از پیش مشخص شده تخصیص مییابد ولی در خوشه بندی هیچ اطلاعی از خوشهها وجود ندارد و به عبارتی خود خوشهها نیز از دادهها استخراج میشوند. به بیان دیگر در دسته بندی مفهوم دسته در یک حقیقت خارجی نهفته است حال آنکه مفهوم خوشه در نهان فواصل میان رکورد هاست. مشهورترین تقسیم بندی الگوریتمهای خوشه بندی به شرح زیر است:
2-1- خوشه بندی افرازی (Centroid Based Clustering) :
تقسیم مجموعه دادهها به زیرمجموعههای بدون همپوشانی، به طریقی که هر داده دقیقاً در یک زیر مجموعه قرار داشته باشد. این الگوریتمها بهترین عملکرد را برای مسائل با خوشههای به خوبی جدا شده از خود نشان میدهند. از الگوریتمهای افرازی میتوان به موارد زیر اشاره نمود:
2-1-1- الگوریتم خوشه بندی K-Means :
در این الگوریتم عملاً مجموعه دادهها به تعداد خوشههای از پیش تعیین شده تقسیم میشوند. در واقع فرض میشود که تعداد خوشهها از ابتدا مشخص میباشند. ایده اصلی در این الگوریتم تعریف K مرکز برای هر یک از خوشهها است. بهترین انتخاب برای مراکز خوشهها قرار دادن آنها (مراکز) در فاصله هر چه بیشتر از یکدیگر میباشد. پس از آن هر رکورد در مجموعه داده به نزدیکترین مرکز خوشه تخصیص مییابد. معیار محاسبه فاصله در این مرحله هر معیاری میتواند باشد. این معیار با ماهیت مجموعه داده ارتباط تنگاتنگی دارد. مشهورترین معیارهای محاسبه فاصله رکوردها در روش خوشه بندی معیار فاصله اقلیدسی و فاصله همینگ میباشد. لازم به ذکر است در وضعیتی که انتخاب مراکز اولیه خوشهها به درستی انجام نشود، خوشههای حاصل در پایان اجرای الگوریتم کیفیت مناسبی نخواهند داشت. بدین ترتیب در این الگوریتم جواب نهائی به انتخاب مراکز اولیه خوشهها وابستگی زیادی دارد که این الگوریتم فاقد روالی مشخص برای محاسبه این مراکز میباشد. امکان تولید خوشههای خالی توسط این الگوریتم از دیگر معایب آن میباشد.
2-1-2- الگوریتم خوشه بندی K-Medoids :
این الگوریتم برای حل برخی مشکلات الگوریتم K-Means پیشنهاد شده است، که در آن بجای کمینه نمودن مجموع مجذور اقلیدسی فاصله بین نقاط (که معمولاً به عنوان تابع هدف در الگوریتم K-Means مورد استفاده قرار میگیرد)، مجموع تفاوتهای فواصل جفت نقاط را کمینه میکنند. همچنین بجای میانگین گیری برای یافتن مراکز جدید در هر تکرار حلقه یادگیری مدل، از میانه مجموعه اعضای هر خوشه استفاده میکنند.
2-1-3- الگوریتم خوشه بندی Bisecting K-Means :
ایده اصلی در این الگوریتم بدین شرح است که برای بدست آوردن K خوشه، ابتدا کل نقاط را به شکل یک خوشه در نظر میگیریم و در ادامه مجموعه نقاط تنها خوشه موجود را به دو خوشه تقسیم میکنیم. پس از آن یکی از خوشههای بدست آمده را برای شکسته شدن انتخاب میکنیم و تا زمانی که K خوشه را بدست آوریم این روال را ادامه میدهیم. بدین ترتیب مشکل انتخاب نقاط ابتدایی را که در الگوریتم K-Means با آن مواجه بودیم نداشته و بسیار کاراتر از آن میباشد.
2-1-4- الگوریتم خوشه بندی Fuzzy C-Means:
کارائی این الگوریتم نسبت به الگوریتم K-Means کاملاً بالاتر میباشد و دلیل آن به نوع نگاهی است که این الگوریتم به مفهوم خوشه و اعضای آن دارد. در واقع نقطه قوت الگوریتم Fuzzy C-Means این است که الگوریتمی همواره همگراست. در این الگوریتم تعداد خوشهها برابر با C بوده (مشابه الگوریتم K-Means) ولی برخلاف الگوریتم K-Means که در آن هر رکورد تنها به یکی از خوشههای موجود تعلق دارد، در این الگوریتم هر کدام از رکوردهای مجموعه داده به تمامی خوشهها متعلق است. البته این میزان تعلق با توجه به عددی که درجه عضویت تعلق هر رکورد را نشان میدهد، مشخص میشود. بدین ترتیب عملاً تعلق فازی هر رکورد به تمامی خوشهها سبب خواهد شد که امکان حرکت ملایم عضویت هر رکورد به خوشههای مختلف امکان پذیر شود. بنابراین در این الگوریتم امکان تصحیح خطای تخصیص ناصحیح رکوردها به خوشهها سادهتر میباشد و مهمترین نقطه ضعف این الگوریتم در قیاس با K-Means زمان محاسبات بیشتر آن میباشد. میتوان پذیرفت که از سرعت در عملیات خوشه بندی در برابر رسیدن به دقت بالاتر میتوان صرفه نظر نمود.
2-2- خوشه بندی سلسله مراتبی (Connectivity Based Clustering (Hierarchical Clustering:
در پایان این عملیات یک مجموعه از خوشههای تودرتو به شکل سلسله مراتبی و در قالب ساختار درختی خوشه بندی بدست میآید که با استفاده از نمودار Dendrogram چگونگی شکل گیری خوشههای تودرتو را میتوان نمایش داد. این نمودار درخت مانند، ترتیبی از ادغام و تجزیه را برای خوشههای تشکیل شده ثبت میکند، یکی از نقاط قوت این روش عدم اجبار برای تعیین تعداد خوشهها میباشد (بر خلاف خوشه بندی افرازی). الگوریتمهای مبتنی بر خوشه بندی سلسله مراتبی به دو دسته مهم تقسیم بندی میشوند:
2-2-1- روشهای خوشه بندی تجمیعی (Agglomerative Clustering) :
با نقاطی به عنوان خوشههای منحصر به فرد کار را آغاز نموده و در هر مرحله، به ادغام خوشههای نزدیک به یکدیگر میپردازیم، تا زمانی که تنها یک خوشه باقی بماند.
عملیات کلیدی در این روش، چگونگی محاسبه میزان مجاورت دو خوشه است و روشهای متفاوت تعریف فاصله بین خوشهها باعث تمایز الگوریتمهای مختلف مبتنی بر ایده خوشه بندی تجمیعی است. برخی از این الگوریتمها عبارتند از: خوشه بندی تجمیعی – کمینه ای، خوشه بندی تجمیعی – بیشینه ای، خوشه بندی تجمیعی – میانگینی، خوشه بندی تجمیعی – مرکزی.
2-2-2- روش های خوشه بندی تقسیمی (Divisive Clustering) :
با یک خوشهی دربرگیرندهی همه نقاط کار را آغاز نموده و در هر مرحله، خوشه را میشکنیم تا زمانی که K خوشه بدست آید و یا در هر خوشه یک نقطه باقی بماند.
2-3- خوشه بندی مبتنی بر چگالی (Density Based Clustering):
تقسیم مجموعه داده به زیرمجموعه هایی که چگالی و چگونگی توزیع رکوردها در آنها لحاظ میشود. در این الگوریتم مهمترین فاکتور که جهت تشکیل خوشهها در نظر گرفته میشود، تراکم و یا چگالی نقاط میباشد. بنابراین برخلاف دیگر روشهای خوشه بندی که در آنها تراکم نقاط اهمیت نداشت، در این الگوریتم سعی میشود تنوع فاصله هایی که نقاط با یکدیگر دارند، در عملیات خوشه بندی مورد توجه قرار گیرد. الگوریتم DBSCAN مشهورترین الگوریتم خوشه بندی مبتنی بر چگالی است.
به طور کلی عملکرد یک الگوریتم خوشه بندی نسبت به الگوریتمهای دیگر، بستگی کاملی به ماهیت مجموعه داده و معنای آن دارد.
3- کشف قوانین انجمنی :
الگوریتمهای کاشف قوانین انجمنی نیز همانند الگوریتمهای خوشه بندی به صورت روشهای توصیفی یا بدون ناظر طبقه بندی میشوند. در این الگوریتمها بدنبال پیدا کردن یک مجموعه از قوانین وابستگی یا انجمنی در میان تراکنشها (برای مثال تراکنشهای خرید در فروشگاه، تراکنشهای خرید و فروش سهام در بورس و ...) هستیم تا براساس قوانین کشف شده بتوان میزان اثرگذاری اشیایی را بر وجود مجموعه اشیاء دیگری بدست آورد. خروجی در این روش کاوش، به صورت مجموعه ای از قوانین «اگر-آنگاه» است، که بیانگر ارتباطات میان رخداد توامان مجموعه ای از اشیاء با یکدیگر میباشد. به بیان دیگر این قوانین میتواند به پیش بینی وقوع یک مجموعه اشیاء مشخص در یک تراکنش، براساس وقوع اشیاء دیگر موجود در آن تراکنش بپردازد. ذکر این نکته ضروری است که بدانیم قوانین استخراج شده تنها استلزام یک ارتباط میان وقوع توامان مجموعه ای از اشیاء را نشان میدهد و در مورد چرایی یا همان علیت این ارتباط سخنی به میان نمیآورد. در ادامه به معرفی مجموعه ای از تعاریف اولیه در این مبحث میپردازیم (در تمامی تعاریف تراکنشهای سبد خرید مشتریان در یک فروشگاه را به عنوان مجموعه داده مورد کاوش در نظر بگیرید):
• مجموعه اشیاء: مجموعه ای از یک یا چند شیء. منظور از مجموعه اشیاء K عضوی، مجموعه ای است که شامل K شیء باشد.
برای مثال:{مسواک، نان، شیر}
• تعداد پشتیبانی (Support Count) : فراوانی وقوع مجموعهی اشیاء در تراکنشهای موجود که آنرا با حرف σ نشان میدهیم.
برای مثال: 2=({مسواک، نان، شیر})σ
• مجموعه اشیاء مکرر (Frequent Item Set) : مجموعه ای از اشیاء که تعداد پشتیبانی آنها بزرگتر یا مساوی یک مقدار آستانه (Min Support Threshold) باشد، مجموعه اشیاء مکرر نامیده میشود.
• قوانین انجمنی: بیان کننده ارتباط میان اشیاء در یک مجموعه از اشیاء مکرر. این قوانین معمولاً به شکل X=>Y هستند.
برای مثال:{نوشابه}<={مسواک، شیر}
مهمترین معیارهای ارزیابی قوانین انجمنی عبارتند از:
• Support: کسری از تراکنشها که حاوی همه اشیاء یک مجموعه اشیاء خاص هستند و آنرا با حرف S نشان میدهند.
برای مثال: 2.2=({نان، شیر})S
• Confidence: کسری از تراکنشهای حاوی همه اشیاء بخش شرطی قانون انجمنی که صحت آن قانون را نشان میدهد که با آنرا حرف C نشان میدهند. برخلاف Support نمیتوانیم مثالی برای اندازه گیری Confidence یک مجموعه اشیاء بیاوریم زیرا این معیار تنها برای قوانین انجمنی قابل محاسبه است.
با در نظر گرفتن قانون X=>Y میتوان Support را کسری از تراکنش هایی دانست که شامل هر دو مورد X و Y هستند و Confidence برابر با اینکه چه کسری از تراکنش هایی که Y را شامل میشوند در تراکنش هایی که شامل X نیز هستند، ظاهر میشوند. هدف از کاوش قوانین انجمنی پیدا کردن تمام قوانین Rx است که از این دستورات تبعیت میکند:
در این دستورات منظور از SuppMIN و ConfMIN به ترتیب عبارت است از کمترین مقدار برای Support و Confidence که بایست جهت قبول هر پاسخ نهائی به عنوان یک قانون با ارزش مورد توجه قرار گیرد. کلیه قوانینی که از مجموعه اشیاء مکرر یکسان ایجاد میشوند دارای مقدار Support مشابه هستند که دقیقاً برابر با تعداد پشتیبانی یا همان σ شیء مکرری است که قوانین انجمنی با توجه به آن تولید شده اند. به همین دلیل فرآیند کشف قوانین انجمنی را میتوان به دو مرحله مستقل «تولید مجموعه اشیاء مکرر» و «تولید قوانین انجمنی مطمئن» تقسیم نمائیم.
در مرحله نخست، تمام مجموعه اشیاء که دارای مقدار Support ≥ SuppMIN میباشند را تولید میکنیم. رابطه I
در مرحله دوم با توجه به مجموعه اشیاء مکرر تولید شده، قوانین انجمنی با اطمینان بالا بدست میآیند که همگی دارای شرط Confidence ≥ ConfMIN هستند. رابطه II
3-1- الگوریتم های Apriori ، Brute-Force و FP-Growth:
یک روش تولید اشیاء مکرر روش Brute-Force است که در آن ابتدا تمام قوانین انجمنی ممکن لیست شده، سپس مقادیر Support و Confidence برای هر قانون محاسبه میشود. در نهایت قوانینی که از مقادیر آستانهی SuppMIN و ConfMIN تبعیت نکنند، حذف میشوند. تولید مجموعه اشیاء مکرر بدین طریق کاری بسیار پرهزینه و پیچیده ای میباشد، در واقع روشهای هوشمندانه دیگری وجود دارد که پیچیدگی بالای روش Brute-Force را ندارند زیرا کل شبکه مجموعه اشیاء را به عنوان کاندید در نظر نمیگیرند. همانند تولید مجموعه اشیاء مکرر، تولید مجموعه قوانین انجمنی نیز بسیار پرهزینه و گران است.
چنانچه یک مجموعه اشیاء مکرر مشخص با d شیء را در نظر بگیریم، تعداد کل قوانین انجمنی قابل استخراج از رابطه III محاسبه میشود. (برای مثال تعداد قوانین انجمنی قابل استخراج از یک مجموعه شیء 6 عضوی برابر با 602 قانون میباشد، که با توجه به رشد d؛ سرعت رشد تعداد قوانین انجمنی بسیار بالا میباشد.)
الگوریتمهای متعددی برای تولید مجموعه اشیاء مکرر وجود دارد برای نمونه الگوریتمهای Apriori و FP-Growth که در هر دوی این الگوریتم ها، ورودی الگوریتم لیست تراکنشها و پارامتر SuppMIN میباشد. الگوریتم Apriori روشی هوشمندانه برای یافتن مجموعه اشیاء تکرار شونده با استفاده از روش تولید کاندید است که از یک روش بازگشتی برای یافتن مجموعه اشیاء مکرر استفاده میکند. مهمترین هدف این الگوریتم تعیین مجموعه اشیاء مکرری است که تعداد تکرار آنها حداقل برابر با SuppMIN باشد. ایده اصلی در الگوریتم Apriori این است که اگر مجموعه اشیایی مکرر باشد، آنگاه تمام زیر مجموعههای آن مجموعه اشیاء نیز باید مکرر باشند. در واقع این اصل همواره برقرار است زیرا Support یک مجموعه شیء هرگز بیشتر از Support زیرمجموعههای آن مجموعه شیء نخواهد بود. مطابق با این ایده تمام ابرمجموعههای مربوط به مجموعه شیء نامکرر از شبکه مجموعه اشیاء حذف خواهند شد (هرس میشوند). هرس کردن مبتنی بر این ایده را هرس کردن بر پایه Support نیز عنوان میکنند که باعث کاهش قابل ملاحظه ای از تعداد مجموعههای کاندید جهت بررسی (تعیین مکرر بودن یا نبودن مجموعه اشیاء) میشود.
الگوریتم FP-Growth در مقایسه با Apriori روش کارآمدتری برای تولید مجموعه اشیاء مکرر ارائه میدهد. این الگوریتم با ساخت یک درخت با نام FP-Tree سرعت فرآیند تولید اشیاء مکرر را به طور چشمگیری افزایش میدهد، در واقع با یکبار مراجعه به مجموعه تراکنشهای مساله این درخت ساخته میشود. پس از ساخته شدن درخت با توجه به ترتیب نزولی Support مجموعه اشیاء تک عضوی (یعنی مجموعه اشیاء) مساله تولید مجموعه اشیاء مکرر به چندین زیر مسئله تجزیه میشود، که هدف در هر کدام از این زیر مساله ها، یافتن مجموعه اشیاء مکرری است که به یکی از آن اشیاء ختم خواهند شد.
الگوریتم Aprior علاوه بر تولید مجموعه اشیاء مکرر، اقدام به تولید مجموعه قوانین انجمنی نیز مینماید. در واقع این الگوریتم با استفاده از مجموعه اشیاء مکرر بدست آمده از مرحله قبل و نیز پارامتر ConfMIN قوانین انجمنی مرتبط را که دارای درجه اطمینان بالائی هستند نیز تولید میکند. به طور کلی Confidence دارای خصوصیت هماهنگی (Monotone) نیست ولیکن Confidence قوانینی که از مجموعه اشیاء یکسانی بوجود میآیند دارای خصوصیت ناهماهنگی هستند. بنابراین با هرس نمودن کلیه ابرقوانین انجمنی یک قانون انجمنی یا Confidence (Rx) ≥ ConfMIN در شبکه قوانین انجمنی (مشابه با شبکه مجموعه اشیاء) اقدام به تولید قوانین انجمنی مینمائیم. پس از آنکه الگوریتم با استفاده از روش ذکر شده، کلیه قوانین انجمنی با اطمینان بالا را در شبکه قوانین انجمنی یافت، اقدام به الحاق نمودن آن دسته از قوانین انجمنی مینماید که پیشوند یکسانی را در توالی قانون به اشتراک میگذارند و بدین ترتیب قوانین کاندید تولید میشوند.
جهت آشنائی بیشتر به List of machine learning concepts مراجعه نمائید.
CAPTCHAfa
reCAPTCHA ایدهای است که با نمایش کلمات واقعی و اسکن شده از کتابهای قدیمی، بخشی از مشکلات را حل کرده و از کاربران اینترنت برای شناسایی کلماتی که رایانه توانایی خواندن آنها را ندارد استفاده میکند. (شکل زیر)
با وارد کردن درست هر کلمه، بخشی از یک کتاب، روزنامه، و یا مجلهی قدیمی در رایانه شناسایی و به فرمت دیجیتال ذخیره میشود. به این شکل شما در دیجیتالی کردن متون کاغذی سهیم هستید.
پروژهی reCAPTCHA توسط گوگل حمایت میشود و در این آدرس قرار دارد.
به تازگی تیمی از دانشکده فنی دانشگاه تهران به همراه انستیتو تکنولوژی ایلینویز شیکاگو، پروژه ای بر همین اساس اما برای متون فارسی با عنوان CAPTCHAfa تولید کرده اند (شکل زیر) که در این آدرس در دسترس است. امیدوارم این پروژه به گونه ای تغییر کنه که برای دیجیتالی کردن متنهای پارسی استفاده بشه. در حال حاضر، این پروژه از کلماتی از پیش تعریف شده استفاده میکنه.
متاسفانه این پروژه در حال حاضر فقط توسط برنامههای PHP قابل استفاده است. از این رو بر آن شدم تا اون رو برای برنامههای ASP.NET (هم Web Forms و هم MVC) آماده کنم. برای استفاده از CAPTCHAfa نیاز به یک کلید خصوصی و یک کلید عمومی دارید که از این آدرس قابل دریافت است.
کدهای پروژهی Class Library به شرح زیر است.
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // Captchafa demo for ASP.NET applications // by: Behrouz Rad // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= namespace Captcha { using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Text; using System.Web; public class Captchafa { private static readonly string PRIVATE_KEY = "your private key"; private static readonly string PUBLIC_KEY = "your public key"; private static readonly string CAPTCHAFA_API_SERVER = "http://www.captchafa.com/api"; private static readonly string CAPTCHAFA_VERIFY_SERVER = "http://www.captchafa.com/api/verify/"; private IDictionary<string, string> CaptchafaData { get { HttpContext httpContext = HttpContext.Current; string remoteIp = httpContext.Request.ServerVariables["REMOTE_ADDR"]; string challenge = httpContext.Request.Form["captchafa_challenge_field"]; string response = httpContext.Request.Form["captchafa_response_field"]; IDictionary<string, string> data = new Dictionary<string, string>() { {"privatekey" , PRIVATE_KEY }, {"remoteip" , remoteIp }, {"challenge" , challenge }, {"response" , response } }; return data; } } public static string CaptchafaGetHtml() { return string.Format("<script type=\"text/javascript\" src=\"{0}/?challenge&k={1}\"></script>", CAPTCHAFA_API_SERVER, PUBLIC_KEY); } public bool IsAnswerCorrect() { string dataToSend = this.CaptchafaPrepareDataToSend(this.CaptchafaData); string result = this.CaptchafaPostResponse(dataToSend); return result.StartsWith("true"); } private string CaptchafaPrepareDataToSend(IDictionary<string, string> data) { string result = string.Empty; StringBuilder sb = new StringBuilder(); foreach (var item in data) { sb.AppendFormat("{0}={1}&", item.Key, HttpUtility.UrlEncode(item.Value.Replace(@"\", string.Empty))); } result = sb.ToString(); sb = null; result = result.Substring(0, result.LastIndexOf("&")); return result; } private string CaptchafaPostResponse(string data) { StreamReader reader = null; Stream dataStream = null; WebResponse response = null; string responseFromServer = string.Empty; try { WebRequest request = WebRequest.Create(CAPTCHAFA_VERIFY_SERVER); request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded"; byte[] byteData = Encoding.UTF8.GetBytes(data); request.ContentLength = byteData.Length; dataStream = request.GetRequestStream(); dataStream.Write(byteData, 0, byteData.Length); dataStream.Close(); response = request.GetResponse(); dataStream = response.GetResponseStream(); reader = new StreamReader(dataStream); responseFromServer = reader.ReadToEnd(); } finally { if (reader != null) { reader.Close(); } if (dataStream != null) { dataStream.Close(); } if (response != null) { response.Close(); } } return responseFromServer; } } }
ابتدا ارجاعی به فایل Captchafa.dll ایجاد کنید و سپس در روال Page_Load، کد زیر را قرار دهید. این کار برای تزریق اسکریپ CAPTCHAfa به صفحه استفاده میشود.
if (!IsPostBack) { litCaptcha.Text = Captchafa.CaptchafaGetHtml(); }
litCaptcha، یک کنترل Literal است که اسکریپت تولید شده، به عنوان متن آن معرفی میشود.
بررسی صحت مقدار وارد شده توسط کاربر (مثلاً در روال Click یک دکمه) به صورت زیر است.
Captchafa captchaFa = new Captchafa(); bool isAnswerCorrect = captchaFa.IsAnswerCorrect(); if (isAnswerCorrect) { // پاسخ صحیح است } else { // پاسخ صحیح نیست }
استفاده در پروژههای ASP.NET MVC
ابتدا ارجاعی به فایل Captchafa.dll ایجاد کنید. در ASP.NET MVC بهتره تا فرایند کار رو در یک HTML helper کپسوله کنیم.
public static class CaptchaHelper { public static MvcHtmlString Captchafa(this HtmlHelper htmlHelper) { return MvcHtmlString.Create(Captcha.Captchafa.CaptchafaGetHtml()); } }
بررسی صحت مقدار وارد شده توسط کاربر (پس از ارسال فرم به Server) به صورت زیر است.
[HttpPost] [ActionName("Index")] public ViewResult CaptchaCheck() { Captchafa captchaFa = new Captchafa(); bool isAnswerCorrect = captchaFa.IsAnswerCorrect(); if (isAnswerCorrect) { ViewBag.IsAnswerCorrect = true; } else { ViewBag.IsAnswerCorrect = false; } return View(); }
@using CaptchafaDemoMvc.Helpers; @{ ViewBag.Title = "Index"; } <form action="/" method="post"> @Html.Captchafa(); <input type="submit" id="btnCaptchafa" name="btnCaptchafa" value="آزمایش" /> @{ bool isAnswerExists = ViewBag.IsAnswerCorrect != null; } @if (isAnswerExists) { if ((bool)ViewBag.IsAnswerCorrect == true) { <span id="lblResult">پاسخ صحیح است</span> } else { <span id="lblResult">پاسخ صحیح نیست</span> } } </form>
دموی پروژه رو در این آدرس قرار دادم. پروژهی نمونه نیز از این آدرس قابل دریافت است.
پ.ن: به زودی برخی بهبودها رو بر روی این پروژه انجام میدم.