هیستوگرام (Histogram) و نمودارهای چگالی – راهنمای بصری سازی دادههای تک بُعدی در پایتون


رسم یک متغیر منفرد به نظر کار آسانی میآید. با وجود تنها یک بُعد، نمایش کارآمد دادهها نباید کار دشواری باشد. اغلب افراد بدین منظور از هیستوگرامهای ساده استفاده میکنند. موقعیت مقادیر مختلف، گسترش دادهها و شکل توزیع آنها (نرمال، دارای کشیدگی، دوبخشی و ...) را نشان میدهد. با این حال در برخی موارد هیستوگرام (بافتنگار) به کار نمیآید و میبایست از روشهای دیگری استفاده کنید. کتاب رایگان آنلاین بسیار خوبی برای بصریسازی دادهها وجود دارد که میتوانید از برخی تکنیکهای معرفی شده در آن کتاب به منظور کسب راهنمایی استفاده کنید. در این نوشته قصد داریم تا یک راهنمای پایتون برای پیادهسازی برخی تکنیکهای معرفی شده در این کتاب ارائه کنیم و جایگزینی به نام نمودار چگالی برای هیستوگرامها نشان دهیم که مفید بودن آن به اثبات رسیده است.
در این مقاله نگاهی جامع خواهیم داشت به استفاده از هیستوگرامها و نمودارهای چگالی در پایتون که با استفاده از کتابخانههای matplotlib و seaborn ترسیم میشوند. در سراسر این نوشته ما به بررسی مجموعه دادهای از دنیای واقعی میپردازیم، زیرا منابع زیادی به صورت آنلاین وجود دارند و عذری برای عدم استفاده از دادههای واقعی وجود ندارد. در این نوشته به بصریسازی دادههای NYCflights13 خواهیم پرداخت که شامل بیش از 300،000 مشاهده پروازهای خروجی از نیویورک در سال 2013 است. ما روی نمایش یک متغیر خاص متمرکز شدهایم که این متغیر برابر با «تأخیر پروازهای ورودی به دقیقه» است. کد کامل این مقاله به صورت Jupyter Notebook روی گیتهاب در دسترس است.
همواره بهتر است که پیش از شروع به ترسیم دادهها، آنها را به صورت مقدماتی بررسی کنیم. میتوان دادهها را وارد قاب داده panda کرد و 10 ردیف نخست را نمایش داد:
import pandas as pd # Read in data and examine first 10 rows flights = pd.read_csv('data/formatted_flights.csv') flights.head(10)
تأخیرهای پروازهای ورودی به دقیقه هستند و مقادیر منفی به معنی رسیدن زودتر از موعد پرواز است (مشخص شد که پروازها غالباً زودتر از موعد به فرودگاه میرسند؛ مگر این که ما داخلشان باشیم!) بیش از 300،000 پرواز وجود داشت که دستکم 60 تا 120 دقیقه تأخیر داشتند. ستون دیگر این قاب داده حاوی نام خطوط هوایی بود که به منظور مقایسه استفاده میشود.
هیستوگرامها
روش عالی برای شروع بررسی یک متغیر خاص، استفاده از هیستوگرام یا بافتنگار است. هیستوگرام متغیر را به دستههایی تقسیم میکند، نقاط دادهای را در هر دسته میشمارد و دستهها را روی محور x نمایش داده و تعداد نقاط را روی محور y نشان میدهد. در این مورد دستهها به صورت بازههای زمانی بودند که میزان تأخیر پروازها را نمایش میدادند و تعداد نیز همان عدد آن دسته از تأخیرها در هر بازه زمانی بود. عرض دسته مهمترین پارامتر برای هیستوگرام است و همواره باید مقادیر متفاوت عرض بررسی شوند تا بهترین مقدار برای هر مجموعه دادهای مشخص شود.
برای ایجاد یک بافتنگار ساده در پایتون میتوانیم از matplotlib یا seaborn استفاده کنیم. کدی که در ادامه آمده است، تابعهایی را نشان میدهد که در هر دو کتابخانه برای ایجاد شکلهای متناظر فراخوانی میشوند. برای ایجاد نمودار، عرض دسته و تعداد دستههای هیستوگرام بیان میشود. در این نمودار از دستههایی استفاده شده است که طولی به میزان 5 دقیقه دارند، یعنی تعداد دستهها در کل محدوده (از 60- تا 120 دقیقه) تقسیم بر عرض دسته شده که 5 دقیقه است (bins = int(180/5)).
#Import the libraries import matplotlib.pyplot as plt import seaborn as sns # matplotlib histogram plt.hist(flights['arr_delay'], color = 'blue', edgecolor = 'black', bins = int(180/5)) # seaborn histogram sns.distplot(flights['arr_delay'], hist=True, kde=False, bins=int(180/5), color = 'blue', hist_kws={'edgecolor':'black'}) # Add labels plt.title('Histogram of Arrival Delays') plt.xlabel('Delay (min)') plt.ylabel('Flights')

در اغلب هیستوگرامهای ساده از کد matplotlib استفاده میشود زیرا سادهتر است؛ اما در ادامه برای ایجاد توزیعهای متفاوت از تابع distplot کتابخانه seaborn استفاده خواهد شد که از نظر آشنایی با روشهای متفاوت نیز خوب است.
چرا برای عرض دسته از مقدار 5 دقیقه استفاده شده است؟ تنها روش برای یافتن عرض بهینه این است که چند مقدار را امتحان کنید. در ادامه برخی تصاویر با عرض دستههای مختلف نمایش داده شدهاند. در نهایت باید گفت که پاسخ درست یا نادرست در مورد عرض دسته وجود ندارد؛ اما مقدار 5 دقیقه به این دلیل انتخاب شده است که به نظر میرسد توزیع دادهها را بهتر نمایش میدهد.
# Show 4 different binwidths for i, binwidth in enumerate([1, 5, 10, 15]): # Set up the plot ax = plt.subplot(2, 2, i + 1) #Draw the plot ax.hist(flights['arr_delay'], bins = int(180/binwidth), color = 'blue', edgecolor = 'black') # Title and labels ax.set_title('Histogram with Binwidth = %d' % binwidth, size = 30) ax.set_xlabel('Delay (min)', size = 22) ax.set_ylabel('Flights', size= 22) plt.tight_layout() plt.show()

انتخاب عرض دسته، تأثیر معنیداری بر نمودار حاصل دارد. عرضهای کم برای دسته ممکن است باعث شلوغ شدن نمودار شوند؛ اما از طرف دیگر عرضهای بزرگ نیز ممکن است تفاوتهای ظریف را نشان ندهند. Matplotlib به طور خودکار عرض دسته معقول را انتخاب میکند؛ اما بهتر است شما پس از امتحان کردن چند مقدار مختلف خودتان به یک عرض دسته مطلوب برسید. همانطور که قبلاً اشاره کردیم مقدار صحیح یا نادرست وجود ندارد و صرفاً میبایست گزینههای مختلف بررسی شود تا مشخص شود که کدام مقدار برای هر مجموعه داده مناسبتر است.
چه زمانی نمیتوان از هیستوگرام استفاده کرد؟
هیستوگرامها روشی عالی برای شروع بررسی یک متغیر خاص در هر دسته هستند. با این حال وقتی میخواهیم توزیعهای یک متغیر را در چند دسته از دادهها مقایسه کنیم، هیستوگرامها با مانع خوانایی مواجه میشوند. برای نمونه اگر بخواهیم توزیعهای زمان رسیدن پروازها را بین خطوط هوایی مختلف مقایسه کنیم، میتوانیم از رویکردهای مختلفی استفاده کنیم. یکی از رویکردهای ممکن که البته چندان بهینه نیست، تجمیع هیستوگرام همه ایرلاینها روی یک نمودار واحد است.
توجه داشته باشید که محور y برای نشان دادن تعداد متفاوت پروازها بین خطوط هوایی مختلف نرمالسازی شده است. برای این کار آرگومان norm_hist = True به تابع sns.distplot ارسال میشود.
این نمودار چندان مفید نیست! همه ستونهایی که روی هم افتادهاند در مجموع باعث شدهاند که امکان خواندن مقادیر و مقایسه بین خطوط هوایی وجود نداشته باشد. در ادامه برخی راهحلهای رایج برای این مشکل را بررسی کردهایم.
راهحل اول: هیستوگرامهای کنار هم
در این روش به جای این که خطوط هوایی مختلف روی هم بیفتند، میتوانیم آنها را در کنار هم نمایش دهیم. به این منظور فهرستی از تأخیرهای رسیدن را برای هر خط هوایی تهیه میکنیم و سپس آن را به صورت یک فهرست از فهرستها به تابع plt.hist ارسال میکنیم. در این روش باید رنگهای مختلفی برای هر خط هوایی معرفی کنیم و به هر یک برچسب متفاوتی بزنیم تا آنها از را هم متمایز کنیم. کد مورد نیاز که شامل مرحله ایجاد فهرستها برای هر خط هوایی است در ادامه آمده است:
# Make a separate list for each airline x1 = list(flights[flights['name'] == 'United Air Lines Inc.']['arr_delay']) x2 = list(flights[flights['name'] == 'JetBlue Airways']['arr_delay']) x3 = list(flights[flights['name'] == 'ExpressJet Airlines Inc.']['arr_delay']) x4 = list(flights[flights['name'] == 'Delta Air Lines Inc.']['arr_delay']) x5 = list(flights[flights['name'] == 'American Airlines Inc.']['arr_delay']) # Assign colors for each airline and the names colors = ['#E69F00', '#56B4E9', '#F0E442', '#009E73', '#D55E00'] names = ['United Air Lines Inc.', 'JetBlue Airways', 'ExpressJet Airlines Inc.'', 'Delta Air Lines Inc.', 'American Airlines Inc.'] # Make the histogram using a list of lists # Normalize the flights and assign colors and names plt.hist([x1, x2, x3, x4, x5], bins = int(180/15), normed=True, color = colors, label=names) # Plot formatting plt.legend() plt.xlabel('Delay (min)') plt.ylabel('Normalized Flights') plt.title('Side-by-Side Histogram with Multiple Airlines')
اگر فهرستی از فهرستها را به matplotlib ارسال کنیم به طور خودکار ستونها را کنار هم قرار میدهد. در این مورد عرض دسته به 15 دقیقه تغییر یافته است، چون در غیر این صورت نمودار شلوغ میشد؛ اما حتی با وجود این اصلاح نیز تصویر حاصل چندان مفید نیست. اطلاعات بسیار زیادی برای پردازش وجود دارند که همگی به یکباره عرضه میشوند، ستونها با برچسبها همراستا نیستند و همچنان امکان مقایسه بین خطوط هوایی مختلف به دشواری میسر است. زمانی که نموداری ترسیم میکنیم، میخواهیم درک دادهها برای بیننده تا حد امکان ساده باشد و با در نظر گرفتن این معیار، تصویر فوق موفق نبوده است. بنابراین در ادامه، راهحل دوم را بررسی میکنیم.
راهحل دوم: ستونهای روی هم (پشتهای)
ما میتوانیم به جای این که ستونها را در کنار هم نمایش دهیم، آنها را بر وی هم سوار کنیم. این کار از طریق ارسال پارامتر stacked = true به تابع هیستوگرام ممکن میشود:
# Stacked histogram with multiple airlines plt.hist([x1, x2, x3, x4, x5], bins = int(180/15), stacked=True, normed=True, color = colors, label=names)
بدیهی است که در این روش نیز بهبود چندانی در رسم نمودار حاصل نشده است. در این نمودار هر ایرلاین به صورت یک بخش از کل برای هر دسته نمایش داده میشود؛ اما امکان هیچ مقایسهای تقریباً وجود ندارد. برای نمونه در تأخیر 15- تا 0 دقیقه آیا میتوان گفت که کدام یک از خطوط هوایی یونایتد ایرلاینز و جتبلو اندازه دسته بزرگتری دارند؟ احتمالاً امکان پاسخ به این سؤال وجود ندارد. به طور کلی نمودارهای روی هم (پشتهای) چندان محبوب نیستند، زیرا تفسیر آنها دشوار است. البته در برخی موارد مانند بصریسازی نسبتها شاید مناسب باشند. هر دو راهحل فوق با استفاده از هیستوگرامها اجرا شدند که موفقیتآمیز نبودند و بنابراین اینک نوبت آن است که نمودارهای چگالی را بررسی کنیم.
نمودار چگالی
در ابتدا باید توضیح دهیم که نمودار چگالی چیست؟ نمودار چگالی نسخه هموار و پیوستهای از هیستوگرام است که از روی دادهها تخمین زده میشود. رایجترین شکل تخمین به نام تخمین چگالی هسته یا کرنل (Kernel density estimation) نامیده میشود. در این روش یک منحنی پیوسته (کرنل) در همه نقاط منفرد دادهای رسم میشود و سپس همه این منحنیها به هم اضافه میشوند تا یک تخمین چگالی هموار به دست آید. این کرنل در نمودارهای گاوسی بیشتر استفاده میشود (که یک منحنی زنگوله گاوسی در هر نقطه دادهای ایجاد میکند). اگر فکر میکنید این توضیح کمی گیجکننده است به نمودار زیر نگاه کنید:

در این شکل هر خط سیاهرنگ کوچک روی محور x نشاندهنده یک نقطه دادهای است. کرنلهای منفرد (در این مثال نمودارهای گاوسی هستند) به صوت خطچین قرمز بالای هر نقطه ترسیم شدهاند. خط ممتد آبی رنگ با جمع زدن تابعهای گاوسی منفرد ایجاد شده و در نهایت نمودار کلی چگالی را تشکیل داده است.
محور x مقدار متغیر را همانند هیستوگرام نشان میدهد؛ اما محور y دقیقاً چه کاری انجام میدهد؟ محور y در یک نمودار چگالی برابر با تابع چگالی احتمال برای تخمین چگالی کرنل است. با این حال باید در مورد این که این یک چگالی احتمال است و نه احتمال، کمی محتاطتر باشیم. تفاوت این دو آن است که چگالی احتمال مقدار احتمال بر واحد در محور x است.
برای تبدیل آن به یک احتمال واقعی باید مساحت ناحیه زیر منحنی را برای بازه معین روی محور x بیابیم. شاید کمی سردرگم کننده باشد؛ اما از آنجا که این چگالی احتمال است و نه احتمال، محور y میتواند مقادیری بالاتر از 1 بپذیرد. تنها الزام در نمودار چگالی آن است که مساحت کلی زیر منحنی در مجموع برابر با 1 باشد. به طور کلی محور y در یک نمودار چگالی به صورت مقداری در نظر گرفته میشود که برای مقایسه نسبت بین دستههای مختلف مورد استفاده قرار میگیرد.
نمودارهای چگالی در Seaborn
برای این که در کتابخانه Seaborn نمودارهای چگالی را ایجاد کنیم میتوانیم از تابعهای distplot و یا kdeplot استفاده کنیم. ما به استفاده از تابع distplot ادامه میدهیم، زیرا این تابع به ما کمک میکند که توزیعهای چندگانه را با یک فراخوانی تابع ترسیم کنیم. برای مثال، میتوانیم یک نمودار را که همه تأخیرهای رسیدن پروازها را نشان میدهد روی هیستوگرام متناظر ترسیم کنیم:
# Density Plot and Histogram of all arrival delays sns.distplot(flights['arr_delay'], hist=True, kde=True, bins=int(180/5), color = 'darkblue', hist_kws={'edgecolor':'black'}, kde_kws={'linewidth': 4})

این منحنی یک نمودار چگالی را نشان میدهد که نسخه هموارتری از هیستوگرام است. محور y بر حسب چگالی و هیستوگرام به طور پیشفرض، نرمالسازی شده است به طوری که مقیاس محور y آن با مقیاس نمودار چگالی یکسان است.
نمودار چگالی همانند عرض دسته در بافتنگار پارامتری دارد که پهنای باند (bandwidth) نامیده میشود و کرنلهای منفرد را تغییر میدهد. این پارامتر تأثیر زیادی روی نتیجه نهایی نمودار دارد. کتابخانه مربوطه مقدار معقولی برای این پارامتر انتخاب میکند (به طور پیشفرض از روش تخمین اسکات استفاده میکند) و برخلاف عرض دسته در هیستوگرام، معمولاً افراد ترجیح میدهند که از مقدار پیشفرض پهنای باند در نمودار چگالی استفاده کنند. با این حال، میتوانیم از پهنای باند متفاوتی استفاده کنیم تا ببینیم آیا نتیجه بهتر میشود یا نه. در این نمودار روش تخمین اسکات به طور پیشفرض استفاده میشود که به نظر میرسد بهترین گزینه است.

توجه کنید که نتایج انتخاب پهنای باند عریضتر این است که توزیع هموارتر میشود. همچنین میبینیم که گرچه دادهها به مقادیر بین 60- تا 120 محدود شده است؛ ولی نمودار چگالی فراتر از این محدوده نیز گسترش یافته است. این یکی از مشکلات بالقوه در نمودار چگالی است. چون این نمودار، توزیع هر نقطه دادهای را محاسبه میکند و میتواند دادههایی تولید کند که خارج از کرانهای دادههای اصلی قرار گیرند. این وضعیت میتواند به این معنی باشد که در نتیجه نهایی مقادیری روی محور x وجود دارند که ناممکن هستند و هرگز در دادههای اصلی وجود نداشتهاند. باید اشاره کرد که میتوان کرنل را تغییر داد تا توزیعی که در هر نقطه دادهای رسم میشود، تغییر یابد و از این رو توزیع کلی تعدیل شود. با این حال در اغلب کاربردها، کرنل پیشفرض، تابع گاوسی و تخمین پهنای باند پیشفرض به خوبی پاسخگو هستند.
راهحل سوم: نمودار چگالی
اینک که چگونگی تشکیل یک نمودار چگالی را دانستید و با آنچه نمایش میدهد آشنا شدید، در ادامه نشان میدهیم که چگونه این نمودار میتواند مشکل بصریسازی تأخیرهای زمان رسیدن پروازها در ایرلاینهای چندگانه را حل کند. برای نمایش توزیعها روی یک نمودار واحد میتوانیم روی ایرلاینها، چرخهای تعریف کنیم که هر بار تابع distplot را فراخوانی میکند و تخمین چگالی کرنل به مقدار True و هیستوگرام به مقدار False تنظیم میشود. کدی که نمودار چگالی را برای چند ایرلاین ترسیم میکند در ادامه آمده است:
# List of five airlines to plot airlines = ['United Air Lines Inc.', 'JetBlue Airways', 'ExpressJet Airlines Inc.'', 'Delta Air Lines Inc.', 'American Airlines Inc.'] # Iterate through the five airlines for airline in airlines: # Subset to the airline subset = flights[flights['name'] == airline] # Draw the density plot sns.distplot(subset['arr_delay'], hist = False, kde = True, kde_kws = {'linewidth': 3}, label = airline) # Plot formatting plt.legend(prop={'size': 16}, title = 'Airline') plt.title('Density Plot with Multiple Airlines') plt.xlabel('Delay (min)') plt.ylabel('Density')

اینک میتوانیم بگوییم که در نهایت به راهحل مناسب دست یافتهایم. با استفاده از نمودار چگالی میتوانیم به سادگی بین ایرلاین های مختلف مقایسه بکنیم، زیرا این نمودار شلوغی کمتری دارد. اینک که در نهایت به نموداری که میخواستیم رسیدیم، به این نتیجه دست مییابیم که در همه این خطوط هوایی توزیع تأخیرهای رسیدن پروازها تقریباً مشابه هستند. با این وجود، ایرلاین های دیگری نیز در این مجموعه داده هستند که میتوانیم ایرلاین دیگری که مقادیری متفاوت دارد رسم کنیم تا پارامتر اختیاری دیگری را در نمودارهای چگالی معرفی بکنیم که گراف سایهدار نام دارد.
نمودارهای چگالی سایهدار
پر کردن بخش زیرین نمودارهای چگالی به ما کمک میکند تا بین توزیعهای همپوشان تمایز قائل شویم. با این که این روش همواره رویکرد مناسبی محسوب نمیشود؛ اما میتواند به تأکید روی تفاوتهای بین توزیعها کمک کند. برای سایه زدن نمودارهای چگالی میتوانیم پارامتر shade = True را برای آرگومان kde_kws در تابع distplot ارسال کنیم.
sns.distplot(subset['arr_delay'], hist = False, kde = True, kde_kws = {'shade': True, 'linewidth': 3}, label = airline)

این که یک نمودار چگالی سایهدار باشد یا نباشد، همانند هر گزینه دیگری در رسم نمودارها سؤالی است که به خود مسئله بستگی دارد. در این گراف چنین رویکردی باعث میشود که بین دو نمودار در منطقهای که همپوشانی دارند، تمییز بهتری ایجاد شود. اینک بالاخره میتوانیم بگوییم که اطلاعات مفیدی در دست داریم: پروازهای ایرلاین آلاسکا نسبت به ایرلاین یونایتد مقدار زمان بیشتری زودتر از برنامه در مقصد مینشینند. بنابراین دفعه دیگر که خواستید بین این دو تصمیم بگیرید، بهتر میدانید که کدام یک را انتخاب کنید.
نمودارهای Rug
اگر بخواهید همه مقادیر را در یک توزیع دقیق و نه یک چگالی هموار نشان دهید، در این صورت باید از نمودار rug استفاده کنید. این نمودار تکتک نقاط دادهای را روی محور x نمایش میدهد و امکان بصریسازی همه مقادیر واقعی را ایجاد میکند. مزیت استفاده از distplot در seaborn آن است که میتوانیم از یک فراخوانی پارامتر منفرد به صورت rug = True برای رسم این نوع نمودار استفاده کنیم.
# Subset to Alaska Airlines subset = flights[flights['name'] == 'Alaska Airlines Inc.'] # Density Plot with Rug Plot sns.distplot(subset['arr_delay'], hist = False, kde = True, rug = True, color = 'darkblue', kde_kws={'linewidth': 3}, rug_kws={'color': 'black'}) # Plot formatting plt.title('Density Plot with Rug Plot for Alaska Airlines') plt.xlabel('Delay (min)') plt.ylabel('Density')

وقتی نقاط دادهای زیاد باشند، نمودار rug بسیار شلوغ میشود؛ اما در برخی مجموعه دادهها نمایش همه نقاط دادهای میتواند مفید باشد. نمودار rug به ما کمک میکند که ببینیم نمودار چگالی در مکانهایی که دادهای وجود ندارد چگونه دادهها را «ایجاد» میکند، زیرا این نمودار در هر نقطه دادهای یک توزیع کرنل ایجاد میکند. این توزیعها روی محدوده دادههای اصلی گسترش مییابند و این حس را ایجاد میکنند که ایرلاینز آلاسکا میزان تأخیرهایی بیشتر و کمتر از مقادیر ثبت شده نیز دارد. میبایست در خصوص این جعل داده در نمودار چگالی هوشیار باشیم و در این مورد به مخاطبان هشدار بدهیم.
نتیجهگیری
امیدواریم این نوشته در مورد گزینههای مختلفی که برای بصریسازی یک متغیر خاص از میان یک یا چند دسته وجود دارد به شما کمک کرده باشد. نمودارهای تک متغیره دیگری نیز مانند نمودارهای چگالی تجمعی نمونهای (empirical cumulative density plots) و نمودار Q-Q اختصار عبارت (quantile-quantile plots) نیز وجود دارند؛ اما در این نوشته به این مقدار بسنده میکنیم. اگر فکر میکنید گزینههای موجود زیاد و گیجکننده هستند، باید بدانید که جای نگرانی نیست، چون تمرین کردن باعث میشود که انتخاب گزینه مناسب، راحتتر باشد.
به علاوه باید بدانید که همیشه یک انتخاب بهینه وجود ندارد و تصمیم «صحیح» به ترجیح افراد و اهداف بصریسازی بستگی دارد. نکته خوب این است که صرفنظر از اینکه چه کاری میخواهید بکنید، میتوانید آن را در پایتون انجام دهید. بصریسازی ابزار مؤثری برای انتقال نتایج است و دانستن همه گزینههای موجود باعث میشود که بتوانید بهترین تصاویر را برای دادههای خود تهیه کنید.
اگر این مقاله مورد توجه شما قرار گفته است، احتمالاً به موارد زیر نیز علاقهمند خواهید بود:
- گنجینه آموزشهای برنامه نویسی کاربردی متلب — از مقدماتی تا پیشرفته
- آموزش برنامهنویسی R و نرمافزار R Studio
- گنجینه آموزش های برنامه نویسی پایتون (Python)
- مجموعه آموزشهای پردازش تصویر و پردازش سیگنال
- مجموعه آموزشهای آمار، احتمالات و دادهکاوی
==
سلام با تشکر از مطالب مفید شما
یک سوال: فایل data/flights.csv
رو از کجا باید داشته باشیم. ممنون
سلام و ممنون از توجه شما.
دیتای این نتبوک ژوپیتر در این آدرس (+) قابل دسترسی است.
با تشکر.