<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های پوریا گنجی</title>
        <link>https://virgool.io/feed/@pooryaganji1368</link>
        <description>علاقه مند به تحلیل داده. لینکدین:https://www.linkedin.com/in/pooryaganji</description>
        <language>fa</language>
        <pubDate>2026-06-07 07:59:46</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/9432/avatar/21d3Cn.png?height=120&amp;width=120</url>
            <title>پوریا گنجی</title>
            <link>https://virgool.io/@pooryaganji1368</link>
        </image>

                    <item>
                <title>کدوم اتاق فرار بریم؟ (داده های سایت t4f.ir)</title>
                <link>https://virgool.io/Namafar/%DA%A9%D8%AF%D9%88%D9%85-%D8%A7%D8%AA%D8%A7%D9%82-%D9%81%D8%B1%D8%A7%D8%B1-%D8%A8%D8%B1%DB%8C%D9%85-lwgdxjefre35</link>
                <description>از سرگرمی های مورد علاقه من اتاق فرار هست و هر بار که میخوام با دوستام برم کلی میگردم یه جای خوب پیدا کنم. دوست داشتم بدونم کدوم اتاق فرارها بیشترین و بهترین امتیاز رو دارن. از علاقه های دیگه ام هم اسکرپ کردن کردن دیتا هست خب فکر کردم چرا که نه و شاید این دیتا به درد بقیه هم بخوره. معروف ترین سایت در حال حاضر t4f.ir هست که برای تهران 310 تا اتاق فرار داره و خوشبختانه خیلی راحت بود گرفتن دیتا ها از این سایت. سایت t4f.irاین سایت اطلاعات مختلفی از بازی ارایه میده از جمله عنوان هر بازی، تعداد رای، میانگین رای، تیم ارائه دهنده، آدرس و غیره. یه ملاک خوب برای اینکه بفهمیم بازی ارزش رفتن داره یا نه اینه که تعداد رای ها و میانگین امتیاز بالا باشه. نمودار زیر این مورد رو نشون میده. محور افقی تعداد رای هر بازی و محور عمودی میانگین امتیاز رو نمایش میده. از اونجایی که امکان نداشت همه اتاق فرار ها رو به اسم روی نمودار مشخص کنم بازی های دارای بیشترین امتیاز رو انتخاب کردم تا اگه خواستید بهشون سر بزنید. به مورد دیگه که میتونه جالب باشه محله های با بیشترین تعداد بازی هست که نشون میده تو محدوده تهرانپارس تعداد بیشترین بازی وجود داره. مکان های بعدی با بیشترین تعداد بازی رو میتونید ببینید</description>
                <category>پوریا گنجی</category>
                <author>پوریا گنجی</author>
                <pubDate>Wed, 27 Oct 2021 00:20:15 +0330</pubDate>
            </item>
                    <item>
                <title>کدام بهتر است Pandas یا SQL (مورد مطالعه: بازگشت مشتری)</title>
                <link>https://virgool.io/@pooryaganji1368/%DA%A9%D8%AF%D9%88%D9%85-%D8%A8%D9%87%D8%AA%D8%B1%D9%87-pandas-%DB%8C%D8%A7-sql-%D9%85%D9%88%D8%B1%D8%AF-%D9%85%D8%B7%D8%A7%D9%84%D8%B9%D9%87-%D8%A8%D8%A7%D8%B2%DA%AF%D8%B4%D8%AA-%D9%85%D8%B4%D8%AA%D8%B1%DB%8C-q9jbw1e8axfd</link>
                <description>برای تحلیل داده ها ابزارهای مختلفی استفاده میشود. pandas یکی از ماژول های محبوب در محیط پایتون برای تحلیل داده های به شکل جدول است و انواع عملیات برای تمیزسازی، جابجایی و تغییر ساختار داده ها را پشتیبانی میکند. اما در مواردی که داده در پایگاه داده ذخیره شده اند مساله متفاوت است. در تحلیل داده های کسب وکاری که نیاز به واکشی داده از پایگاه داده وجود دارد، اگر بخواهیم از پایتون برای تحلیل داده ها استفاده کنیم. دو راه پیش رو داریم. راه اول: ابتدا داده های خام را از منبع داده استخراج کنیم و از ابزارهایی نظیر pandas برای تمیزسازی و تحلیل استفاده کنیم. راه دوم: به کمک ابزارهای مناسب نظیر  SQL داده ها را تاجای ممکن خالص سازی کنیم و تنها بخش نهایی مورد نیاز را واکشی کنیم. در این مقاله این دو راه حل را با هم مقایسه میکنیم و نقطه قوت و ضعف هر کدام را مقایسه میکنیم. برای بررسی مساله تحلیل داده های مشتریان و بازگشت مشتری (customer retention) از این دو راه حل کمک میگیریم.بازگشت مشتری: یکی از توانایی های کلیدی هر کسب وکار برای حفظ مشتری و تبدیل آن به مشتری دایمی و جلوگیری از جذب او توسط رقباست. این موضوع تابعی از میزان رضایت مندی مشتری در رفع نیازهایش توسط محصولات کسب و کار بوده و از عوامل اصلی موفقیت کسب و کار به شمار میرود. چرا که راضی کردن و جذب  مجدد مشتری فعلی به مراتب برای کسب و کار کم هزینه تر است. داده ها مربوط به یک کسب وکار جواهرفروشی انلاین بوده و شامل 113303 رکورد و ستون های زیر است.روش مورد استفاده ما برای حل این مساله، حالت ساده ای از بازگشت مشتری است. به این صورت که مشتری بعد از هر خرید، اگر در همان ماه جاری یا ماه بعد از آن مجددا خرید کرد به عنوان مشتری با بازگشت (retention) محسوب شده و در صورتی که بیش از آن وقفه در خرید داشته باشد مثلا تا خرید بعدی سه ماه فاصله بیفتد، به عنوان مشتری دارای تاخیر (delay) در خرید به شمار میرود. دسته دیگر مورد بررسی ما مشتریان جدید و بدون سابقه خرید قبلی هستند. بر اساس هر دو روش داده های مورد نیاز را به دست اورده و در نهایت نمودار تعداد مشتریان قرار گرفته در هر دسته را به شکل نمودار حطی رسم میکنیم.راه اول:در این روش برای به دست اوردن مشتریان در دسته های retention ، delay و new و داده های نهایی به طور کامل از کوئری نویسی SQL استفاده میکنیم. (دستور timeit%% در jupyter notebook برای سنجش زمان لازم برای اجرای کد)%%timeit
import pandas as pd   
import pyodbc 
# Some other example server values are
# server = &#039;localhost\sqlexpress&#039; # for a named instance
# server = &#039;myserver,port&#039; # to specify an alternate port
server = &#039;*&#039; 
database = &#039;*&#039; 
username = &#039;*&#039; 
password = &#039;*&#039; 
cnxn = pyodbc.connect(&#039;DRIVER={ODBC Driver 17 for SQL Server};SERVER=&#039;+server+&#039;;DATABASE=&#039;+database+&#039;;UID=&#039;+username+&#039;;PWD=&#039;+ password)
query=r&amp;quot&amp;quot&amp;quot
#ابتدا داده های سال 2019 را انتخاب میکنیم
with orders as 
(SELECT month([event_time]) as month_num,[user_id]
FROM [jewelry_clean_v2] )
,orders_label as
# فاصله بین خریدهای هر مشتری را حساب میکنیم برچسب ها را مطابق مقادیر گفته شده اختصاص میدهیم 
# labels =  retention , delay , new
    (select [user_id],month_num,return_month,return_month-month_num as gap,case when return_month-month_num=1 or return_month-month_num=0 then &#039;retention&#039; when return_month-month_num&gt;1 then &#039;delayed&#039; else null end as label from
    (select [user_id],month_num,lead(month_num,1) 
    over(partition by [user_id] order by month_num) as return_month from orders) as sub)
#در نهایت داده های حاوی مشتریان حدید و قدیمی را با هم ادغام میکنیم
select sub.month_num,count(sub.[user_id]) as count,&#039;new&#039; as label from (select min(month_num) as month_num,[user_id] from orders_label group by [user_id]) as sub group by sub.month_num 
union select return_month,count(distinct [user_id]),label from orders_label group by return_month,label    &amp;quot&amp;quot&amp;quot
df=pd.read_sql(query,cnxn)در نهایت داده های مطابق زیر خواهیم داشت. به عنوان نمونه برای ماه دوم (February) 2305 مشتری جدید داشتیم و 920 مشتری خود را تکرار کردند (خرید قبلیشان در همان ماه یا ماه قبلی بوده است). از نظر عملکرد زمانی این کد با 0.12 ثانیه اجرا شد.output:10 loops, best of 3: 124 ms per loopراه دوم:به عنوان راه دوم فراخوانی داده های خام اولیه را با یک کوئری ساده SQL انجام داده و سایر عملیات روی داده ها را با راه حل اول مقایسه میکنیم.%%timeit
import pandas as pd
import pyodbc 
server = &#039;*&#039; 
atabase = &#039;*&#039; 
username = &#039;*&#039; 
password = &#039;*&#039; 
cnxn = pyodbc.connect(&#039;DRIVER={ODBC Driver 17 for SQL Server};SERVER=&#039;+server+&#039;;DATABASE=&#039;+database+&#039;;UID=&#039;+username+&#039;;PWD=&#039;+ password)
query=r&amp;quot&amp;quot&amp;quotselect event_time,user_id from [jewelry_clean_v2]&amp;quot&amp;quot&amp;quot
df_pandas=pd.read_sql(query,cnxn)فقط مقادیر مورد نیاز را از جدول فراخوانی کردیم و داخل متغیر df_pandas ذخیره کردیم و سایر مراحل توسط ماژول pandas انجام شده.df_pandas[&#039;event_time&#039;]=df_pandas[&#039;event_time&#039;].apply(lambda x:x.month)
df_pandas.sort_values(by=[&#039;user_id&#039;,&#039;event_time&#039;],ascending=True,inplace=True)
df_pandas[&#039;shift&#039;]=df_pandas.groupby([&#039;user_id&#039;])[&#039;event_time&#039;].shift(-1)
df_pandas[&#039;label&#039;]= (df_pandas[&#039;shift&#039;] - df_pandas[&#039;event_time&#039;])
df_pandas[&#039;label&#039;]=df_pandas[&#039;label&#039;].apply(lambda x:&#039;retention&#039; if (x==0)|(x==1) else (&#039;delay&#039; if x&gt;1 else None))
df_pandas.sort_values([&#039;user_id&#039;,&#039;event_time&#039;],inplace=True)
new_users=df_pandas[[&#039;event_time&#039;,&#039;user_id&#039;]].groupby(&#039;user_id&#039;).min().reset_index()
new_users=new_users.groupby(&#039;event_time&#039;).count().reset_index()
df_pandas=df_pandas[~df_pandas.duplicated()]
df_pandas=df_pandas[[&#039;shift&#039;,&#039;label&#039;,&#039;user_id&#039;]].groupby([&#039;shift&#039;,&#039;label&#039;]).count().reset_index()
df_pandas.columns=[&#039;month&#039;,&#039;label&#039;,&#039;count&#039;]
new_users[&#039;label&#039;]=&#039;new&#039;
new_users.columns=[&#039;month&#039;,&#039;count&#039;,&#039;label&#039;]
df_pandas=df_pandas.append(new_users,ignore_index=True)
همچنین از نظر عملکرد زمانی این کد در 0.7 ثانیه به اجرا درامدoutput:1 loop, best of 3: 702 ms per loop
از دیدگاه فنی:نوشتن کوئری  SQL پیچیده بوده و فهم آن مشکل تر از ماژول pandas به نظر میرسد. فیلتر داده ها در هر بار و انتخاب فیلتر مجدد روی فیلتر قبلی باعث افزایش پیچیدگی کوئری میشود. اما pandas توابع بسیار متنوعی دارد که بسیاری از عملیات روی داده ها را نسبت به کوئری نویسی ساده میکند هرچند از نظر عملکردی با توجه به نتایج و اختلاف حدود 7 برابری نتایج به دست امده مشخص میشود اجرای کوئری SQL تا جای ممکن و تنها خواندن داده های آماده جهت تحلیل از پایگاه داده، مزیت بسیاری دارد. در این مساله زمان و سخت افزار قابل توجهی اشغال نشد اما در حجم داده های بالا و در موارد حساس به زمان پاسخ گویی مثل مواردی که در تعامل با کاربر قرار داریم قطعا کوئری SQL مزیت زیادی نسبت به pandas دارد. گرچه برای پردازش داده های حجیم ماژول های دیگری هم توسعه داده شده است و بسته به شرایط باید تکنولوژی و ابزار مناسب استفاده شود.از دیدگاه کسب وکار: تعداد مشتریانی که در هر ماه خرید کردند و دسته های مربوطه به شکل زیر است. بیشترین نعداد مشتری در ماه سوم برای خرید اول جذب شده است ولی روند جذب مشتری تا ماه ششم نزولی شده است. ضمن اینکه روند تکرار خرید تقریبا روندی ثابت داشته است. تکرار خرید بستگی زیادی به نوع محصول دارد. مثلا برای کالاهای مصرفی تکرار با نرخ بالاتر اتفاق میفتد و احتمال خرید مشتری در صورت ایجاد وقفه کمتر میشود چرا که با احتمال بالایی مشتری جذب رقبا شده است. همچنین مدل های توزیع و فروش عامل مهم دیگر در تکرار خرید بوده و محصولات دارای حق اشتراک با نرخ نسبتا ثابت و دفعات مشخصی تکرار میشوند که باید در تحلیل مورد توجه قرار بگیرند. نکته دیگر اهمیت داده ها و نمودارهای تکمیلی نظیر تعداد خریدها یا تعداد مشتریان از دست رفته است که میتواند در تفسیر نتایج موثر باشدتعداد مشتریان در ماه های مختلف و دسته های گوناگون</description>
                <category>پوریا گنجی</category>
                <author>پوریا گنجی</author>
                <pubDate>Sun, 26 Sep 2021 21:24:41 +0330</pubDate>
            </item>
                    <item>
                <title>مقایسه دو روش مختلف تحلیل آماری (A/B تست)</title>
                <link>https://virgool.io/@pooryaganji1368/%D9%85%D9%82%D8%A7%DB%8C%D8%B3%D9%87-%D8%AF%D9%88-%D8%B1%D9%88%D8%B4-%D9%85%D8%AE%D8%AA%D9%84%D9%81-%D8%AA%D8%AD%D9%84%DB%8C%D9%84-%D8%A2%D9%85%D8%A7%D8%B1%DB%8C-ab-%D8%AA%D8%B3%D8%AA-w9eivgoh2u4e</link>
                <description>اگه کار تحلیل داده انجام داده باشید حتما به این مورد برخوردید که برای یک آزمون آماری بخش تئوریک مسئله چالش داشته باشد. مثلا محاسبه فاصله اطمینان برای میانه یک نمونه آماری با توزیع نامشخص. در چنین مواردی علاوه بر نیاز به دانستن تئوری آماری کلاسیک و فرض های درست آماری، محاسبه آنها ممکن است کار سخت و زمان بری باشد. در این موارد، روش جایگزین مدلسازی آماری میتواند بسیار کمک کننده باشد. یک روش جایگزین در این مورد رویکرد آمار محاسباتی (computational statistics) است. این رویکرد که در سال های اخیر و با افزایش توان محاسباتی کامپیوترها مورد توجه بیشتری قرار گرفته بر مبنای اجرای مسائل آماری توسط کامپیوتر شکل گرفته است. تکنیک هایی مثل permutation و bootstrapping واژه های اشناتری هستند که به وسیله این رویکرد پیاده سازی میشوند. برای آشنایی ابتدایی با این روش و کاربرد آن میتوانید از این ویدیو و این مخزن گیت هاب استفاده کنید.  ویدیو مربوط به یکی از ارائه ها در کنفرانس scipy سال 2017 توسط نویسنده کتاب های معروف think stats و think Bayes است.تولید نمونه مصنوعی توسط bootstrapping (منبع)معمولا درآمار با این مساله روبرو هستیم که یک یا تعدادی نمونه داریم و قصد داریم از نمونه ها حدس هایی درباره جامعه بزنیم و یا اینکه چقدر مطمئنیم تفاوت مشاهده شده بین نمونه ها تصادفی نیست. یکی از چالش های اصلی کم بودن تعداد نمونه هاست در این موارد کمک گرفتن از bootstrapping میتواند راهگشا باشد و تعداد قابل قبولی نمونه مصنوعی ایجاد کند. این نمونه ها اگه به صورت تصادفی تولید شوند و نمونه اولیه تا حد خوبی نماینده جامعه باشد نتایج جالبی داشته و میتواند با مدلسازی های کلاسیک آماری رقابت کند. در ادامه برای یه مساله A/B تست این دو روش رو با هم مقایسه میکنیمبه صورت خلاصه  A/B تست یه روش تست محصول است که در آن کاربران به دو گروه تقسیم میشوند. گروه کنترل که ویژگی پیش فرض  قدیمی رو تجربه میکنند و یک گروه آزمایشی که ویژگی جدیدی در محصول مشاهده میکنند. اینکه شرایط طراحی این ویژگی ها چطور باید باشد یا اینکه نمونه گیری به چه صورت انجام شود نیاز به بررسی جداگانه دارد.بازی cookie catsبرای طرح مساله از یکی از دیتاست های کگل استفاده میکنیم و میتوانید از اینجا دانلود کنید. این دیتاست مربوط به یک بازی موبایل است. تغییر مورد مطالعه در اینجا، تغییر زمان وقفه بین بازی(احتمالا برای نمایش تبلیغ به بازیکن) است. یک گروه در مرحله 30 و گروه دیگر در مرحله 40 بازی دچار وقفه شده و مجبورند برای ادامه بازی مدتی صبر کنند (تبلیغ تماشا کنند). در نظر داریم بررسی کنیم تغییری در بازگشت بازیکن به بازی بعد از 7 روز، در این دو حالت وجود دارد یا خیر.df=pd.read_csv(&#039;cookie_cats.csv&#039;)
df[[&#039;userid&#039;,&#039;version&#039;,&#039;retention_7&#039;]].head()userid :کد هربازیکن version : شامل دو ورژن مختلف مورد تست retention_7: مقدار باینری شامل بازی یا عدم بازی بازیکن  بعد از 7 روزدر این مثال دقیقا مشخص نیست کدام گروه کنترل و کدام گروه آزمایش است. نمونه A را به عنوان نمونه کنترل و نمونه B را به عنوان نمونه آزمایش در نظر میگیریم.#ورژن A 
a=df[df[&#039;version&#039;]==&#039;gate_30&#039;] 
#ورژن B
b=df[df[&#039;version&#039;]==&#039;gate_40&#039;]
برای ورژن A بازی (44700 بازیکن) حدود 19 درصد (8502 بازیکن) بعد از 7 روز هنوز برای بازی کردن به بازی سر زدنددر حالیکه برای ورژن B بازی (45489 بازیکن) حدود 18.2 درصد (8279 بازیکن) بعد از 7 روز هنوز برای بازی کردن به بازی سر زدنداما ایا این تفاوت از نظر اماری معنی دار است؟ چقدر محتمل است که این تفاوت به صورت تصادفی اتفاق افتاده باشد؟روش اول:ابتدا روش کلاسیک t-test برای تست احتمال تصادفی بودن تفاوت مشاهده شده در دو نمونه بررسی میشود. احتمال بازی کردن یا نکردن این بازی از نوع احتمالی با دو پیشامد است و توزیع دو اسمی. در صورت کفایت تعداد نمونه ها np&gt;5  (n تعداد نمونه و p احتمال پیشامد) میتواند با تقریب مناسبی به عنوان توزیع نرمال در نظر گرفته شود. N_cont = a[&#039;retention_7&#039;].count()  # تعداد نمونه کنترل
N_exp = b[&#039;retention_7&#039;].count()  # تعداد نمونه آزمایش
X_cont = a[&#039;retention_7&#039;].sum()  # تعداد بازیکنی که برای بازی مجدد برگشته (در گروه کنترل) 
X_exp = b[&#039;retention_7&#039;].sum()  # تعداد بازیکنی که برای بازی مجدد برگشته (در گروه آزمایش)
p_pool = (X_cont + X_exp)/(N_cont+N_exp)
se_pool = np.sqrt(p_pool*(1-p_pool)*(1/N_cont + 1/N_exp))
p_cont = X_cont/N_cont #p_cont = 0.19
p_exp = X_exp/N_exp #p_exp = 0.182
d_hat = p_exp - p_cont
# d_hat = 0.008
m = 1.96*se_pool #حاشیه خطا برای سطح اطمینان 95 درصد
cf_min = d_hat-m #حد بالای فاصله اطمینان
cf_max = d_hat+m #حد پایین فاصله اطمینان
#cf_min,cf_max=(-0.003, -0.013)نمونه A و B با هم 0.8 درصد اختلاف دارند و احتمال تعداد بازیکنانی که بعد از 7 روز برای بازی مجددا به بازی سر زدند، در نمونه B حدود 0.8 درصد کاهش پیدا کرده. آیا این اختلاف تصادفی است؟ در سطح اطمینان 95 درصد فاصله اطمینان برای اختلاف بین گروه، بین 0.03 تا 1.3 درصد به دست آمده است (به عبارت دیگر اگر این آزمایش را تکرار کنیم با احتمال 95 درصد مطمئنیم که اختلاف نسبت درصدی دو گروه رقمی بین 0.3 تا 1.3 درصد خواهد بود). پس نتیجه میگیریم این اختلاف با احتمال 95 درصد تصادفی نیست و ورژن B محصول باعث کاهش احتمال بازگشتن بازیکن برای ادامه بازی شده است. هرچند این اختلاف ممکن است ناچیز به نظر برسد.روش دوم:در این روش همان طور که اشاره شد از خود نمونه ها برای انجام استنباط آماری استفاده میشود. در اینجا با استفاده از نمونه ها به ایجاد نمونه های مصنوعی و کاملا تصادفی میپردازیم (bootstrapping) سپس در هر بار پس از ایجاد نمونه ها، اختلاف دو نمونه A و B (همان d_hat روش اول) را محاسبه میکنیم. این کار را 1000 بار تکرار میکنیم. به این ترتیب توزیعی از اختلاف این نمونه های مصنوعی (d_hat) خواهیم داشت. با انتخاب بازه 95 درصد داده ها و حذف 2.5 درصد ابتدایی و انتهایی به بازه اطمینان مورد نظر میرسیم cf_min و cf_max .class Resampler_diff(object):
    def __init__(self, sample1, sample2):
        &amp;quot&amp;quot&amp;quotStores the actual samples.&amp;quot&amp;quot&amp;quot
        self.sample1 = sample1
        self.n1 = len(sample1)
        self.sample2 = sample2
        self.n2 = len(sample2)      
    def resample(self):
        &amp;quot&amp;quot&amp;quotGenerates a new sample by choosing from the original
        sample with replacement.
        &amp;quot&amp;quot&amp;quot
        new_sample1 = numpy.random.choice(self.sample1, self.n1, replace=True)
        new_sample2 = numpy.random.choice(self.sample2, self.n2, replace=True)
        return new_sample1,new_sample2
   def sample_stat(self, samples):
        &amp;quot&amp;quot&amp;quotComputes a sample statistic using the original sample or a
        simulated sample.
        &amp;quot&amp;quot&amp;quot
        return numpy.mean(samples[0])-numpy.mean(samples[1])
    
    def compute_sampling_distribution(self, iters=1000):
        &amp;quot&amp;quot&amp;quotSimulates many experiments and collects the resulting sample
        statistics.
        &amp;quot&amp;quot&amp;quot
        stats = [self.sample_stat(self.resample()) for i in range(iters)]
        return numpy.array(stats)
    
    def plot_sampling_distribution(self):
        &amp;quot&amp;quot&amp;quotPlots the sampling distribution.&amp;quot&amp;quot&amp;quot
        sample_stats = self.compute_sampling_distribution()
        se = sample_stats.std()
        ci = numpy.percentile(sample_stats, [2.5, 97.5])
    
        pyplot.hist(sample_stats, color=COLOR2)
        pyplot.xlabel(&#039;sample statistic&#039;)
        pyplot.xlim(self.xlim)
        text(0.03, 0.95, &#039;CI [%0.4f %0.4f]&#039; % tuple(ci))
        text(0.03, 0.85, &#039;SE %0.4f&#039; % se)
        pyplot.show()
samples=Resampler_diff(a[&#039;retention_7&#039;],b[&#039;retention_7&#039;])
samples.plot_sampling_distribution()توزیع اختلاف نسبت دو ورژن A و B توسط نمونه های مصنوعی ایجاد شدهبه طور جالبی همان نتایج به دست آمده در روش مدلسازی، در روش محاسباتی نیز تکرار شده است و همان بازه 0.3 درصد تا 1.3 درصد با ضریب اطمینان 95 درصد به دست آمده است. هر چند در این مورد محاسبه پارامتر مورد نظر (اختلاف عملکرد ورژن کنترل (A) و ورژن آزمایشی (B)) از طریق آمار کلاسیک با فرض های موجود آسان و قابل انجام بود اما در مواردی مثل محاسبه فاصله اطمینان برای میانه یک نمونه با توزیع نامشخص میتواند مشکل زا بوده و به عنوان روشی جایگزین از آمار محاسباتی و bootstrapping بهره برد.با اسفاده از این آزمون به این نتیجه رسیدیم که ورژن A عملکرد بهتری داشته و به عنوان ورژن برتر در توسعه محصول انتخاب میشود.منابع)آشنایی با آمار محاسباتی:https://www.youtube.com/watch?v=He9MCbs1wgEدوره آمار استنباطی:https://www.udacity.com/course/intro-to-inferential-statistics--ud201دوره A/B testing:https://www.udacity.com/course/ab-testing--ud257</description>
                <category>پوریا گنجی</category>
                <author>پوریا گنجی</author>
                <pubDate>Wed, 15 Sep 2021 21:38:04 +0430</pubDate>
            </item>
                    <item>
                <title>تجربه ساخت داشبورد با Dash plotly</title>
                <link>https://virgool.io/dataio/%D8%AF%D8%A7%D8%B4%D8%A8%D9%88%D8%B1%D8%AF-%D9%82%DB%8C%D9%85%D8%AA-%D8%B3%D9%87%D8%A7%D9%85-%D8%A8%D8%A7-dash-plotly-drnzqdozgzhr</link>
                <description>اخیرا لازم شد تا کار کردن با ابزار dash رو با پایتون یاد بگیرم. از اونجایی که بهترین کار برای یادگیری انجام دادن و تمرین کردنه سعی کردم یه نمونه کاربردی انجام بدم و تو ویرگول بنویسم. dash یه ابزار برای ساخت داشبورد و امکانات خوبی در اختیارتون قرار میده. روب بستر flask نوشته شده و برای بصری سازی از کتابخونه های   Plotly.js و React.js استفاده میکنه یه سری پیچیدگی های این ابزارها رو کم میکنه و محیطی فراهم میکنه که  فقط با دونستن پایتون بتونید یه داشبورد حرفه ای بالا بیارید. اینجا میتونید سری به گالری dash بزنید. متاسفانه این سایت هم مثل خیلی از جاهای دیگه کابرای ایرانی رو تحریم کرده و باید با فیلشکن وارد بشید. یادگرفتن این ابزار ساده هست و من خودم از کورس jose portilla سایت udemy که از اینجا میتونید دانلود کنید، استفاده کردم. اول به مرور و معرفی ابزار dash میپردازیم و بعدش مختصری در مورد داشبوردی که ایجاد کردم و مربوط به بازار بورس امریکا(لینک) هست صحبت میکنیم.معرفی dash:برای اینکه داشبورد سروشکل بگیره باید المان های مختلف رو تو اپلیکیشن بچینید. مثلا به این صورت با یه تیتر شروع میکنیم:import dash_html_components as html  
html.H1(&#039;عنوان داشبورد&#039;)هرچند برای اعمال تنظیمات حرفه ای تر هم دستتون کاملا بازه و میتونید با update_layout هر بلایی که خواستید سر نمودار بیارید. المان های مختلف شامل دکمه، input، فضای قرار گرفتن نمودار و خیلی امکانات دیگه فراهم شده و میتونید لیست کاملی از اونها رو اینجا ببینید. مثل نمونه کد زیر که یه اسلایدر ایجاد میکنه.import dash_core_components as dcc
dcc.RangeSlider(marks={i: &#039;Label {}&#039;.format(i) for i in range(-5, 7)}, min=-5,max=6,value=[-3, 4] )داده هایی که برای بصری سازی و تولید نمودار استفاده میشه ساختار دیتافریم داره و به سادگی یک خط کد زدن به نمودار تبدیل میشه. مثلا ایجاد یه هیستوگرام به همین سادگیه:import plotly.express as px
fig=px.histogram(df, x=&amp;quotcolumn&amp;quot)
fig.update_layout(title,........) تعاملی بودن یه موضوع بسیار مهم در ایجاد داشبوردهاست و اکثر مواقع داشبورد باید با انتخابهای مختلف کاربر آپدیت بشه و بر اساس ورودی های کاربر داده های جدیدی رو نمایش بده. این موضوع با استفاده از callback ها مدیریت میشه و المان های مختلف داشبورد با استفاده از ورودی های جدیدی که بینشون رد و بدل میشه خروجی های جدیدی تولید میکنن و رفتار جدیدی نشون میدن. به عنوان نمونه در نمونه کد زیر مقدار موجود در المان my-input تحت تابع update_output_div به المان my-output انتقال پیدا میکنه@app.callback(Output(component_id=&#039;my-output&#039;, component_property=&#039;children&#039;),Input(component_id=&#039;my-input&#039;,component_property=&#039;value&#039;)) 
def update_output_div(input_value): 
    return &#039;Output: {}&#039;.format(input_value)بررسی داشبورد سهام بورس آمریکا (لینک):ایده اول میتونست این باشه که از داده های بورس ایران استفاده کنم ولی چون جایی که api رایگان ارائه بده پیدا نکردم از داده های بورس امریکا و سایت alpha vantage استفاده کردم. از اینجا میتونید دسترسی رایگان والبته محدود، به api این سایت رو داشته باشین. دریافت داده ها از api و تبدیل به دیتافریم بسیار سادست و با کتابخونهpandas_datareder انجام میشهdata=pandas_datareader.av.time_series.AVTimeSeriesReader(symbols=symbol, function=&#039;TIME_SERIES_DAILY&#039;, start=start_date, end=end_date, retry_count=3, pause=0.1, session=None, chunksize=25, api_key=&#039;alphavantage api key&#039;)df=data.read().reset_index()به این ترتیب میشه تحلیل های مختلف مثل میانگین تغییرات قیمت ، ایجاد نمودار و ... رو ایجاد کرد و از طریقcallback به المان های مختلف فرستاد. یه چالش در این قسمت ایجاد دیتافریم از ورودی کاربر واستفاده از دیتافریم در قسمت های مختلف داشبورد بود. تو موارد مشابه که نیاز دارید از دیتا تو قسمت های مختلف گزارش استفاده کنید،راه های مختلفی وجود داره مثل ذخیزه سازی در المان های مختلف یا ذخیره در دیتابیس های موقت. اینجا توضیح بیشتری در این مورد داده شده. راهی که من استفاده کردم ذخیره سازی دیتا با فرمت json و سپس ذخیره کردن در یک المان DIV و خارج از دید کاربر و سپس استفاده در قسمت های مختلف گزارش بود.یه سایت جالب دیگه که ازش استفاده کردم stocktwits هست. این سایت که شبیه سایت توییتر طراحی شده، شبکه اجتماعی سرمایه گذاران و معامله گران هست و حدود پنج میلیون عضو داره. تو این سایت میتونید پست های نماد مورد نظرتون رو ببینید و خودتون پست منتشر کنید. یکی از قابلیت های این سایت تگگذاری پست ها هست به این صورت که پست هایی که حاوی پیامی مبنی بر صعود (Bullish) یا نزول (Bearish) نمادها هستن، توسط علامت‌های مربوطه تگ گذاری شدننکته اخر اینکه میتونید برای deploy کردن و تست از سرویس میزبانی ابری heroku استفاده کنید. اینجا توضیحات مربوطه داده شده.مرسی از وقتی که واسه مطالعه پست گذاشتید و امیدوارم به دردتون بخوره. ایده و نظری اگه دارید خوشحال میشم درمیون بزارید :)</description>
                <category>پوریا گنجی</category>
                <author>پوریا گنجی</author>
                <pubDate>Fri, 05 Mar 2021 10:36:57 +0330</pubDate>
            </item>
                    <item>
                <title>فیلم گردی با فیلیمو (بخش دوم: متن کاوی و دسته بندی فیلم ها)</title>
                <link>https://virgool.io/dataio/%D9%81%DB%8C%D9%84%D9%85-%DA%AF%D8%B1%D8%AF%DB%8C-%D8%A8%D8%A7-%D9%81%DB%8C%D9%84%DB%8C%D9%85%D9%88-%D8%A8%D8%AE%D8%B4-%D8%AF%D9%88%D9%85-%D9%85%D8%AA%D9%86-%DA%A9%D8%A7%D9%88%DB%8C-%D9%88-%D8%AE%D9%88%D8%B4%D9%87-%D8%A8%D9%86%D8%AF%DB%8C-%D9%81%DB%8C%D9%84%D9%85-%D9%87%D8%A7-ng4si0wjgnbn</link>
                <description>منبع: باشگاه خبرنگاران جواندر بخش اول به کمک مدلسازی گراف رابطه بین بازیگران فیلمها رو بررسی کردیم. در این بخش در دو قسمت مجزا ابتدا با داشبوردی برای جستجو در داده ها آشنا میشیم. سپس بر اساس مدل ساده ای به دسته بندی فیلم ها میپردازیمقسمت اولبرای دسترسی به داشبورد کلیک کنیدداشبوردی که برای جستجو در داده ها استفاده میکنیم با کمک ابزار محبوب من :) یعنی power bi تهیه شده. جدول پایین داشبورد اطلاعات جامعی از فیلم ها از قبیل کارگردان، لینک دسترسی به فیلم روی سایت فیلیمو ،بازیگران، سال ساخت، معرفی فیلم در اختیارتون قرار میده و دو تا شکل بالای داشبورد به عنوان فیلتر عمل میکنن. نمودار میله ای سمت چپ به کارگردان های مختلف روی محور افقی و تعداد کارهای اونها اشاره داره. به عنوان نمونه منوچهر هادی و هاتف علیمردانی که پرکارترین کارگردان ها هم هستن، هر کدوم 6 فیلم در مجموعه داده ها دارن. با کلیک روی هر کدوم از اونها میتونیم اطلاعات رو بر اساس همون کارگردان فیلتر کنیم.شکل زیر نشون میده چطور با کلیک روی لینک فیلم به صفحه فیلم روی سایت فیلیمو هدایت میشینبه کمک جدول سمت راست میتونیم بر اساس موارد مختلف از قبیل اسم فیلم، کارگردان، بازیگر و حتی محتوای فیلم جستجو کنیم (شکل زیر جستجو در محتوا بر اساس کلمه پلیس رو نشون میده). جستجو بر اساس فیلم های شهاب حسینیدر قسمت دوم به طور مختصر از دسته بندی (classification) در یادگیری ماشین و اصطلاحات پردازش متن صحبت میکنیم و برای اجرای کار از زبان پایتون استفاده میکنیم.قسمت دوماین بخش به مراحل مختلف اجرای یک مدل دسته بندی برای پیش بینی ژانر فیلم ها بر اساس متن معرفی فیلم اختصاص داره. هرچند توضیحات قسمت معرفی فیلم، خیلی مختصر نوشته شدن و تنوع فیلم در بیشتر ژانرها برای آموزش مدل کافی نیست. ولی همین مراحل در سایر مسائل قابل پیاده سازی هست. به همین دلیل برای ارزیابی فرایند، تمام مراحل رو بر روی مورد مشابهی از سایت دیوار تکرار میکنیم.دسته بندی (classification) نوعی روش یادگیری ماشین هست که جزیی از روش های با نظارت (supervised learning) محسوب میشه.در روش های با نظارت داده ها دارای برچسب (label) هستن و هدف، رسیدن به الگوی مناسب (توسط داده های پیشین و برچسب هر کدام) برای پیش یبنی برچسب داده های جدید هست.مساله مورد نظر رو به این صورت طرح میکینم: قصد داریم با در نظر گرفتن متن معرفی فیلم ها به عنوان متغیر ورودی (feature)، ژانر فیلم رو به عنوان متغیر خروجی (target) تشخیص بدیم.import pandas as pd
df=pd.read_csv(&#039;filimo.csv&#039;,encoding=&#039;utf-8&#039;)
dfابتدا پراکندگی ژانرها رو برررسی میکنیمdf[&#039;genres&#039;].value_counts().plot(kind=&#039;barh&#039;)بیشترین فروانی مربوط به ژانر خانوادگی اجتماعی هست که به تنهایی تقریبا نیمی از داده ها رو شامل میشه (تعداد فیلم ها= 360).برای اینکه بتونیم از داده های متنی به صورت متغیرهای ورودی (feature) استفاده کنیم باید به طریقی از فرمت متنی به فرمت عددی تبدیل کنیم. برای این کار تکنیک های زیادی وجود داره مثل:-bag of words-word vectors-tfidfصندوقچه کلمات (bag of words) تکنینکی هست که در این پست استفاده میکنیم. در این روش هر کلمه ای که در مجموعه داده ها قرار داره به عنوان متغیر ورودی (feature) در نظر گرفته میشه. مفهوم صندوقچه کلمات به مجموعه متغیرهای ورودی اشاره داره. به این صورت که هر نمونه (sample) در مجموعه که در اینجا متن معرفی فیلم هست، به کلمات سازنده تجزیه میشه و کلماتی که قبلا در صندوقچه کلمات وجود نداشتن (غیر تکراری) به مجموعه اضافه میشن. در نهایت مجوعه ای از تمام کلمات موجود در داده ها به عنوان متغیرهای ورودی خواهیم داشت. با توجه به شرایط مساله ما، حضور و یا عدم حضور کلمه در هر نمونه اهمیت داره اما تعداد تکرار کلمات اهمیت چندانی نداره. مثلا وجود یا عدم وجود کلمه پلیس، کافیه تا مشخص بشه ژانر فیلم پلیسیه و تعداد تکرار ملاک نیست. در این مواقع ساده ترین روش مشابه شکل بالا انتخاب حالت باینری برای متغیرهاست. حضور یا عدم حضور کلمه (term) در نمونه (document) مشخص کننده مقدار 0 و1 برای متغیرهاست.نکته دیگه در مورد داده های متنی نرمال سازی (normalization) و لماتایز (lemmatization) کلمه هاست. نرمال سازی یعنی یکسان سازی کلمات از نظر نگارشهای مختلف. مثلا نگارش کلمه کتابها و کتاب ها نباید باعث بشه پردازش متفاوتی روی کلمات صورت بگیره و نباید این دو نوع نگارش باعث ایجاد دو متغیر در صندوقچه کلمات بشه. یکی از این دو نوع نگارش مبنا قرار میگیره و سایر نگارش ها یکسان سازی میشه. لماتایز مشابه نرمالسازی باعث یکسان سازی کلمات میشه با این تفاوت که کلمات هم ریشه یکسان سازی میشن. مثلا دو کلمه دستم و دستش، تنها در ضمیر متصل تفاوت دارن و معناهای متفاوتی ندارن و باید اونها رو یکسان سازی کنیم. توضیح اضافه: اگه قبلا با مفهوم مشابهی به نام stemming (یکی دیگه از روش های ریشه یابی) آشنا باشید، میدونید که عبارت حاصل از عمل lemmatization معنی دار هست در صورتی که در مورد stemming الزما ابن طور نیست.پردازش هایی که در مورد داده های متنی اشاره کردیم، برای زبان انگلیسی ابزارهای متنوعی دارن. معروف ترین اونها spacy و nltk هستن. برای زبان فارسی در پایتون، هضم تنها ابزار موجوده که به صورت عمومی عرضه شده. هر چند ابزارهایی به صورت وب سرویس وجود دارن و در حال توسعه هستن (مثل واکاویک و text-mining).به کمک هضم پردازشهای مورد نیاز رو انجام میدیم و ستون جدیدی (processed) برای داده های پردازش شده ایجاد میکنیم.normalizer = Normalizer()
lemmatizer = Lemmatizer()
stemmer=Stemmer()
def processor(x):
     s=&#039;&#039;&quot;
     x=re.sub(r&#039;\(|\)|،|\.&#039;,&#039; &#039;,x)
     normed=normalizer.normalize(x)
     for i in word_tokenize(normed):
         s=s+&quot; &quot;+lemmatizer.lemmatize(i)
     return s
 df[&#039;processed&#039;]=df.desc.apply(processor)مقایسه سطر اول داده ها، قبل از پردازش(desc) و بعد از پردازش (processed):print(df.loc[0,&#039;desc&#039;])
print(df.loc[0,&#039;processed&#039;])

output:در فیلم گام های شیدایی ، جولیا به خدمت ارتش ایالات متحده درآمده و تلاش دارد مداركی كه در حین انجام وظیفه در این كشور به دست آورده به دوست خبرنگار خود برساند. در جریان این اتفاقات یكی از پرده های سناریو آزادسازی عراق به تصویر كشیده می شود....
در فیلم گام شیدا جولیا به خدمت ارتش ایالات متحده درآمده و تلاش داشت#دار مدارک که در حین انجام وظیفه در این کشور به دست آورده به دوست خبرنگار خود رساند#رسان در جریان این اتفاقات یک از پرده سناریو آزادسازی عراق به تصویر کشید#کش
متغیرهای ورودی (X) و خروجی (y) رو انتخاب میکنیم و داده های آموزش و تست رو جدا میکنیم:X=df[&#039;processed&#039;]
y=df[&#039;genres&#039;]
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.2, random_state = 0)داده های متنی رو به کمک تکنیک صندوقچه کلمات به فرمت عددی تبدیل میکنیم.from sklearn.feature_extraction.text import CountVectorizer
with open(&quot;Persian_StopList.txt&quot;,encoding=&#039;utf-8&#039;) as file:
    stop=[i.strip() for i in file]
count_vect = CountVectorizer(stop_words=stop,binary=True)
X_train_tf = count_vect.fit_transform(X_train)نکته قابل اشاره در تکه کد بالا کلمات ایست (stop words) هستن. کلمات ایست، به کلماتی گفته میشه که بار معنایی خاصی در متن ندارن. کلماتی مثل(از ، در، با، برای و...). در مدلسازی این کلمات معمولا به عنوان متغیرهای زاید حذف میشن. این کلمات بسته به زمینه مطالعه و کاربرد ممکنه متفاوت باشن. اگه به دسته بندی فیلمها برگردیم، در متن معرفی فیلم ها کلماتی مثل بازیگر،فیلم و... وجود دارن که کمکی به تشخیص ژانر فیلم نمیکنن یا به عبارت دیگه نمیتونیم از روی این کلمات ژانر فیلم رو حدس بزنیم(کاری که مدل ما قراره انجام بده، دقیقا مشابه همینه). حذف این کلمات معمولا کارایی مدل رو افزایش میده.بعد از پیش پردازش داده ها نوبت به آموزش و اجرای مدل میرسه. یکی از الگوریتم هایی که برای دسته بندی متن مناسبه Naive Bayes هست. این مدل بر اساس احتمالات شرطی  (conditional probability)  کار میکنه و بر اساس کلمات هر نمونه و دسته های مختلف (ژانرهای مختلف) دسته با بیشترین احتمال رو پیش بینی میکنه. بعد از انجام تمام مراحل پیش پردازش در نهایت مدلسازی رو انجام میدیم.from sklearn.naive_bayes import BernoulliNB
nb=BernoulliNB(binarize=None)
nb.fit(X_train_tf,y_train)داده های تست (X_test_tf) رو باتوجه به صندوقچه کلمات آماده میکنیم. دقت مدل (نسبت پیش بینی های درست به کل پیش بینی ها) به این صورت به دست میاد.X_test_tf = count_vect.transform(X_test)
nb.score(X_test_tf,y_test)
output:  0.6197183098591549برای سنجش مدل نیاز به شاخص هایی داریم. یکی از شاخص ها برای این کار، مقایسه با dummy classifier هست. در این روش مدلی بر اساس ویژگی های داده ها به دست میاد که بر اساس فرض های ساده به وجود اومده. با استفاده از تکه کد زیر مدلی  میسازیم که بر اساس پرتکرارترین ژانر کار میکنه (به پارامتر strategy=&quot;most_frequent&quot; دقت کنید). قبلا دیدیم که ژانر خانوادگی، اجتماعی بیشترین فراوانی رو در بین سایر ژانرها داره. مدل زیر بر مبنای همین فرض کار میکنه و برچسب تمام داده های تست رو (خانوادگی، اجتماعی) در نظر میگیره (بدون اینکه طبق متغیرهای ورودی آموزش ببینه). اما نکته جالب اینجاست که دقیقا همون دقت مدل naive bayes رو به دست میاره. from sklearn.dummy import DummyClassifier
dummy=DummyClassifier(strategy=&quot;most_frequent&quot;)
dummy.fit(X_train_tf,y_train)
X_test_tf = count_vect.transform(X_test)
dummy.predict(X_test_tf)
 
 output:array([&#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;,
       &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;,
       &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;,
       &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;,
       &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;,
       &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;,
       &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;,
       &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;,
       &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;,
       &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;,
       &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;,
       &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;,
       &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;,
       &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;,
       &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;,
       &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;,
       &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;,
       &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;,
       &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;,
       &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;,
       &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;,
       &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;,
       &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;,
       &#039;خانوادگی,اجتماعی&#039;, &#039;خانوادگی,اجتماعی&#039;], dtype=&#039;&lt;U16&#039;)dummy.score(X_test_tf,y_test)
output: 0.6197183098591549پس مدل ما (naive bayes) از نظر فنی فاقد ارزشه. راه حلهای مختلفی برای بهبود مدل وجود داره. مثل انتخاب سایر الگوریتم های دسته بندی (که در این مورد خاص بهبود خاصی ایجاد نشد)، جمع آوری داده های بیشتر(در صورت امکان) و...با نگاه دقیق تر به مجموعه داده ها به نظر میرسه توضیحات معرفی فیلم برای تشخیص ژانر کافی نباشه. هرچند با افزایش حجم داده ها احتمالا دقت مدل افزایش پیدا میکنه.بد نیست همین مدل و فرایند رو در مورد مجموعه داده های بزرگتر (حدود یک میلیون آگهی) و احتمالا دقیق تر سایت دیوار بررسی کنیم. داده های سایت دیوار شامل اطلاعات متنوعی هستن. ستون های مورد نظر ما، متن آگهی و دسته مورد نظر آگهی هاست. divar[[&#039;cat1&#039;,&#039;desc&#039;]]متن آگهی (desc) و دسته آگهی(cat1)فراوانی دسته های مختلف:divar[&#039;cat1&#039;].value_counts().plot(kind=&#039;barh&#039;)تمام مراحل پیش پردازش شامل حذف کلمات ایست، normalization ، lemmatization و صندوقچه کلمات دقیقا مشابه قبل انجام میشه. در نهایت مدلسازی با الگوریتم naive bayes انجام میشه و دقت مدل با dummy classifier مقایسه میشه.X=divar[&#039;processed&#039;]
y=divar[&#039;cat1&#039;]
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.2)
count_vect = CountVectorizer(stop_words=stop,binary=True)
X_train_tf = count_vect.fit_transform(X_train)

nb=BernoulliNB(binarize=None)
nb.fit(X_train_tf,y_train)
X_test_tf = count_vect.transform(X_test)
nb.score(X_test_tf,y_test)
output:  0.856095343123029مقایسه با dummy classifier (مدلی که برای تمام نمونه ها پرتکرار ترین دسته (for-the-home) رو در نظر میگیره)from sklearn.dummy import DummyClassifier
dummy=DummyClassifier(strategy=&quot;most_frequent&quot;)
dummy.fit(X_train_tf,y_train)
X_test_tf = count_vect.transform(X_test)
dummy.score(X_test_tf,y_test)
output: 0.35734323911234933همون طور که خروجی های بالا نشون میده مدلی که روی داده های سایت دیوار آموزش دیده دقت خوبی داره  (دقت حدود 85 درصد) و نسبت به dummy classisfier برتری داره (دقت حدود 35 درصد). بررسی دو نمونه مختلف به خوبی نشون داد محدودیت های استفاده از مدل ها چطور نمود پیدا میکنن و در صورت عدم وجود داده های مناسب و به تعداد کافی نمیشه انتظار معجزه داشت.دسته بندی متن یکی از حوزه های پرکاربرد تحلیل داده محسوب میشه. مسائلی مثل شناسایی اسپم (spam detection)، تحلیل احساسات، اتوماسیون کارها و... میتونه بخشی از کابردهای این حوزه باشه. سپاس از وقتی که برای حوندن این پست صرف کردین. امیدوارم براتون مفید باشه.ایمیل: pooryaganji1368@gmail.comتوییترلینکدیناینستاگرام</description>
                <category>پوریا گنجی</category>
                <author>پوریا گنجی</author>
                <pubDate>Fri, 19 Apr 2019 17:31:21 +0430</pubDate>
            </item>
                    <item>
                <title>چطور برنده مسابقات اینستاگرامی رو مشخص کنیم</title>
                <link>https://virgool.io/fboard/%DA%86%D8%B7%D9%88%D8%B1-%D8%A8%D8%B1%D9%86%D8%AF%D9%87-%D9%85%D8%B3%D8%A7%D8%A8%D9%82%D8%A7%D8%AA-%D8%A7%DB%8C%D9%86%D8%B3%D8%AA%D8%A7%DA%AF%D8%B1%D8%A7%D9%85%DB%8C-%D8%B1%D9%88-%D9%85%D8%B4%D8%AE%D8%B5-%DA%A9%D9%86%DB%8C%D9%85-qmwy8cxmrjwx</link>
                <description>اگر از اینستاگرام استفاده میکنید حتما با مسابقات اینستاگرامی آشنا هستین. خیلی از کسب وکارها و حتی واینرها از این مسابقات برای افزایش فالوور استفاده میکنن. معمولا روال کار به این صورته که شرکت کننده ها باید جواب سوالی رو بدن و تعدادی از دوستان خودشون رو منشن کنن. اما اینستاگرام ابزاری برای اینکه چطور نتیجه ارزیابی بشه، نداره و تعیین اینکه چه کسانی جواب درست دادن و تعداد خاصی از دوستانشون رو منشن کردن ساده نیست. در این مورد هم طبق معمول :) ابزارهای خارجی زیادی هستن ولی در ایران حداقل با جستجویی که من انجام دادم غیر از سایت marketing98 سرویس دیگه ای وجود نداره. هرچند همون خدمات marketing98 به استخراج کامنت ها و در نهایت قرعه کشی محدود میشه. اینکه چه کسانی جواب درست دادن و چند نفر رو منشن کردن به عهده خودتونه. همین موضوع و البته یه سفارش کاری انگیزه ای شد تا ابزار ساده ای رو توسعه بدم که در ادامه با اون آشنا میشیم. همون طور که در شکل مشاهده میکنین برنامه، رابط کاربری ساده ای داره و یه سری ورودی ها رو از کاربر میگیره و خروجی مورد نظر رو به صورت فایل اکسل تحویل میده. رابط کاربریهر پستی در اینستاگرام دارای یک ادرس منحصر به فرد هست که در بالای مرورگرتون قابل مشاهده هست. همین ادرس رو به باکس اول برنامه منتقل میکنیم و سایر تنظیمات دلخواه رو اعمال میکنیم. برای نمونه پیج فروشگاه های زنجیره ای افق کوروش رو انتخاب کردیم. پیج اینستاگرام okalaطراحی برنامه به صورتی هست که میتونیم شرایط مورد نظر(جواب درست و تعداد افرادی که منشن شدن) رو برای کامنت های خروجی در نظر بگیریم. در این صورت فقط کاربرانی که این شرایط رو دارن در خروجی فایل اکسل دیده میشن. اگه تنظیمات خاصی انجام ندیم داده های خام ذخیره میشن که فقط شامل دو ستون کاربران و کامنت ها میشه. در مسابقه افق کوروش سوال مسابقه این هست که حاصل دو تصویر چی میتونه باشه و جواب کالباس هست :) حالا اگر مایل باشیم فقط افرادی که جواب درست دادن و حداقل 1 نفر رو منشن کردن در خروجی اکسل داشته باشیم و بین اونها به صورت رندوم 3 نفر رو برنده اعلام کنیم، باید تنظیمات رو انجام بدیم و اسم فایل خروجی رو انتخاب کنیم و تمام. خروجی فایل اکسل دقیقا حاوی تمام این اطلاعات خواهد بود. ضمنا تیک گزینه (منشن تکراری قبول نیست) رو فعال کردیم و هر کس که افراد تکراری رو منشن کنه فقط یک بار به حساب میاد و منشن های تکراری حذف میشنتنظیمات دلخواهخروجی نهاییدر فایل خروجی okala دو ستون ایجاد شده به نام تعداد کامنت ها و تعداد منشن ها. اگه تمایل داشتین کسی رو که بیشتر از بقیه کامنت گذاشته یا بیشتر از سایرین دوستاشو منشن کرده به عنوان برنده اعلام کنیناپدیت آبان 1400:متاسفانه با تغییرات زیاد API اینستاگرام و تبعات اون، فقط امکان سفارش اختصاصی این نرم افزار وجود داره که هزینه و میزان زمان باید توافق بشه. در صورتی که تمایل داشتین میتونین به من ایمیل بزنین. pooryaganji1368@gmail.com</description>
                <category>پوریا گنجی</category>
                <author>پوریا گنجی</author>
                <pubDate>Mon, 08 Apr 2019 17:50:08 +0430</pubDate>
            </item>
                    <item>
                <title>فیلم گردی با فیلیمو (بخش اول: تحلیل گراف بازیگران)</title>
                <link>https://virgool.io/dataio/%D9%81%DB%8C%D9%84%D9%85-%DA%AF%D8%B1%D8%AF%DB%8C-%D8%A8%D8%A7-%D9%81%DB%8C%D9%84%DB%8C%D9%85%D9%88-%D8%A8%D8%AE%D8%B4-%D8%A7%D9%88%D9%84-%D8%AA%D8%AD%D9%84%DB%8C%D9%84-%DA%AF%D8%B1%D8%A7%D9%81-%D8%A8%D8%A7%D8%B2%DB%8C%DA%AF%D8%B1%D8%A7%D9%86-fimc5mwmogqq</link>
                <description>منبع: بلاگ نماواپیش نوشت: شاید عنوان پست بیشتر مناسب بخش دوم باشه که به دسته بندی فیلم ها بر اساس متن معرفی فیلم ها میپردازیم. این بخش بیشتر به تحلیل اطلاعات بازیگران فیلم ها اختصاص داره.چند سال اخیر شاهد کاهش قدرت تلویزیون و رشد مصرف محتوای ویدیویی بر بستر اینترنت بودیم. یکی از رقبای تلویزیون در این مورد، VOD ها هستن که در ازای پرداخت حق اشتراک مشخصی به ما امکان میدن در هر ساعتی از روز برنامه دلخواه خودمون رو تماشا کنیم. فیلیمو معروف ترین سرویس دهنده تو این حوزه به شمار میره. یکی از قابلیت هایی که فیلیمو برای کاربران فراهم کرده و دسترسی به محتوا رو راحت تر میکنه، دسته بندی بر اساس ژانر و زمان ساخت فیلمه. در ادامه با هم به دسته فیلم های دهه 90 شمسی که شامل حدود 360 فیلم میشه میپردازیم. داده های سایت فیلیمو شامل اسم فیلم، معرفی فیلم، ژانر، بازیگران و سایر عوامل فیلم میشه. با استفاده از اطلاعات بازیگران، روابط بین اونها رو در یک شبکه مدلسازی میکنیم و نگاهی به مهم ترین بازیگران و همکاری هایی که ممکنه اتفاق بیفته، داریم.مدلسازی رو بر اساس مفهوم گراف انجام میدیم. گراف ساختاری شامل اشیای به هم پیوسته هست. در ساده ترین حالت، رابطه دوستی میتونه یک گراف باشه. مثلا من تعدادی دوست دارم و دوستانم به همین ترتیب تعدادی دوست دارن. دوستان دوست من ممکن هست دوست من هم باشن یا نباشن. مشابه رابطه دوستی در شکل زیر. (گرافی که معرفی کردیم دسته گراف غیر جهت دار هست دسته های دیگری از گراف ها هم وجود دارن مثل گراف جهت دار که علاوه بر وجود رابطه، جهت رابطه هم معنی دار هست مثل رابطه پدر و فرزندی).هر شخص در اینجا یک راس (node) حساب میشه و رابطه دوستی، یال (edge) گفته میشه. همین طور تعداد روابط مربوط به هر راس درجه (degree) هر راس محسوب میشه. گراف ها کابردهای متنوعی دارن. نحوه انتشار اخبار در توییتر و شناسایی جریان اطلاعات و کاربران تاثیرگزار در انتشار اطلاعات، شبکه حمل و نقل و شناسایی نقاط مهم و طراحی شبکه به گونه ای که شبکه در حالت کلی پایدار بمونه و با حذف برخی از راس ها مختل نشه و امکان ادامه فعالیت داشته باشه. شبکه های احتماعی و طراحی پیش نهاد دهنده (recommender) بر اساس دوستان مشترک بخشی از کاربردهای تحلیل گراف هست. در مورد داده های فیلیمو ما مجموعه بازیگران رو به عنوان راس، رابطه همبازی بودن به عنوان یال و تعداد همبازی های هر بازیگر رو درجه بازیگر در نظر میگیریم. برای مصورسازی روابط و تحلیل هایی که میتونیم در یک گراف انجام بدیم از نرم افزار  Gephi استفاده کردم. Gephi رابط کاربری نسبتا ساده ای داره و میتونیم انواع داده ها با فرمت های مخالف رو به عنوان ورودی به نرم افزار بدیم، داده ها رو براساس معیارهای مختلف filter کنیم و انواع تحلیل ها رو به راحتی روی داده ها انجام بدیم. هسته نرم افزار به کمک زبان جاوا نوشته شده و امکان افزودن امکاناتی که توسط سایر کاربران توسعه داده شده با نصب plugin ها وجود داره. اطلاعات مورد استفاده ما شامل دو فایل جداگانه برای اطلاعات راس ها (بازیگران) و یال ها (رابطه همبازی بودن) هستن و در دو مرحله داده ها رو import میکنیم (مطابق راهنمای github نرم افزار).اطلاعات راس ها (بازیگران)ستون id: شناسه منحصر به فرد هر بازیگرستون actor: نام بازیگرستون weight: تعداد فیلم هایی که هر بازیگر بازی کردهاطلاعات همبازی بودن ستون source: مبدا یالستون target: مقصد یالستون title: نام فیلمداده های ما در مجموع شامل اطلاعات 1014 بازیگر، 7730 رابطه همبازی بودن و 360 فیلم هست. میانگین تعداد همبازی برای هر بازیگر 15.2به دست امده یعنی هر بازیگر به طور متوسط با 15 نفر همبازی بوده.  بعد از ورود داده ها، موقعیت راس ها روی صفحه به صورت تصادفی انتخاب میشه که میتونیم از طریق  پنجره layout اون رو تغییر بدیم. مثلا اگر مایل باشیم رئوسی که از نظر وزن ( weight) و تعداد روابط (degree) شبیه هم هستن نزدیک هم قرار بگیرن میتونیم از openord استفاده کنیم. به این ترتیب رئوسی که خصوصیاتی مشابه دارن در یک محدوده قرار میگیرن. یا خیلی ساده میتونیم با انتخاب circular layout رئوس رو به ترتیب یک خصوصیت مثلا تعداد فیلم های هر بازیگر (weight) روی محیط یک دایره قرار بدیم. circular layoutدر ادامه انواع layout و موارد استفاده هر کدوم اشاره شدهانواع layoutموارد استفاده انواع layoutبصری سازی داده ها امکانات جالبی رو فراهم میکنه مثلا میتونیم اندازه هر راس رو معادل تعداد فیلم های هر بازیگر (weight) و تعداد افرادی که با اونها همبازی بوده (درجه - degree)  رو به صورت شدت رنگ در نظر بگیریم به این صورت که هر قدر اندازه راس بزرگتر، تعداد فیلم های بیشتر و هرچقدر پررنگ تر تعداد همبازی ها بیشتر. با کلیک روی هر راس، راس های مجاور نمایش داده میشن و به این ترتیب برای هر بازیگر همبازی ها قابل تشخیص میشن.همون طور که در تصویر مشخصه سه بازیگری که بیشترین فیلم رو در مجموعه داده های ما داشتن به ترتیب سحر قریشی، مهران رجبی و بابک حمیدیان بودن. هرکدوم به ترتیب در بیست ویک، نوزده و هفده فیلم حضور داشتن.در ادامه به مرور تعدادی از اصطلاحات و روابط در گراف داده ها میپردازیم.قطر شبکه (network diameter) به معنی حداکثر فاصله موجود بین دو نقطه در شبکه هست. در مجموعه داده های ما بیشترین فاصله بین بازیگران 7 رابطه هست به این معنی که هر بازیگر حداکثر با 7 واسطه با هر بازیگر دیگری ارتباط داره. مثلا بین صدرالدین حجازی و  یاسمن نصرتی این حداکثر فاصله 7 تایی وجود داره ( قطر شبکه 7 است) و کوتاه ترین زنجیره بین این دو بازیگر به این صورته : &#x27;صدرالدین حجازی&#x27;&gt;&gt; &#x27;آزاده ریاضی&#x27;&gt;&gt; &#x27;زهره حمیدی&#x27;&gt;&gt; &#x27;سحر قریشی&#x27;&gt;&gt; &#x27;لیلا زارع&#x27;&gt;&gt; &#x27;نسیم ادبی&#x27;&gt;&gt; &#x27;عصمت رضاپور&#x27;&gt;&gt; &#x27;یاسمن نصرتی&#x27;میانگین فاصله (average path length) بین تمام بازیگران در شبکه حدود 3 هست یعنی به طور متوسط هر بازیگر با 3 واسطه با بازیگر دیگه در ارتباطه.در هر گرافی امکان داره راس هایی وجود داشته باشن که جدا از سایر راس های مجموعه باشن. به این ترتیب که فقط بین چند راس رابطه وجود داره و خودشون به تنهایی زیرگراف (connected components) تشکیل میدن. در مجموعه داده های ما در مجموع 12 زیرگراف موجوده که در شکل زیر قابل مشاهده هست. حدود 95 درصد از راس ها گراف اصلی رو تشکیل میدن (گراف سبز رنگ) و سایر گراف ها مربوط به بازیگرانی هستن که فقط در یک فیلم حضور داشتن و با همون مجموعه بازیگران همبازی بودن که در ادامه به همین دلیل از نتایج تحلیل کنار گذاشته میشن.برای شناسایی راس های مهم در شبکه معیارهای مختلفی وجود داره مثلا در مورد شبکه حمل و نقل فرودگاهی بین المللی، شهر تهران، راس مهمیه، چون عمده پروازهای بین المللی مبدا و مقصدشون شهر تهرانه و در شبکه به عنوان hub محسوب میشه. معیار closeness centrality یکی دیگه از شاخص ها برای شناسایی راس های مهم در شبکه هست و هر راس از نظر میانگین فاصله با سایر راس ها ارزیابی میشه و طبق این فرض کار میکنه که راس مهم کمترین فاصله رو با سایر راسها در شبکه داره. در ادامه نتیجه ارزیابی بر اساس این شاخص رو مشاهده میکنین:معیار closeness centralityمعیار دیگه برای ارزیابی راس های مهم  betweenness centrality هست و راس ها از نظر میزان تکرار در مسیر سایر راس ها ارزیابی میشن. به این ترتیب راسی مهم هست که به عنوان واسطه ارتباط بین سایر راسها قرار میگیره و طبق معادله زیر به دست میاد. مثلا برای محاسبه betweenness centrality مربوط به راس 20 در شکل زیر به این صورت عمل میکنیم. برای نمونه دو راس 2و 34 رو انتخاب میکنیم. بین دو راس 34 و 2 سه مسیر (کوتاه ترین مسیر)  وجود داره و یکی از این مسیرها از راس 20 میگذره. پس یکی از معادلات برای محاسبه 1/3 هست. حالا باید تمام مسیرهای موجود برای هر جفت راس و تعداد تکرار راس 20 در اونها در شبکه محاسبه بشن و با هم جمع بشن تا betweenness centrality برای راس 20 رو داشته باشیم. نتیجه شاخص betweenness centrality روی داده های فیلیمو:معیار betweenness centralityطبق خروجی های دو جدول بالا، نتایج با هم شباهت هایی  دارن و بیشتر بازیگران بر اساس دو معیار مشترک هستن. روش های دیگه ای برای سنجش راس های مهم در شبکه (مثل eigenvector centrality) وجود داره که براساس شرایط مساله و رفتار شبکه میتونیم از اونها استفاده کنیم.یکی دیگه از سولات مهمی که میشه در مورد رفتار شبکه پرسید اینه که در آینده بین کدوم راس ها احتمال بیشتری وجود داره که اتصال برقرار بشه (link prediction) یا کدوم ترکیب از بازیگران مناسبه و میتونه در فیلم های آینده استفاده بشه.ساده ترین روش اینه که کدوم بازیگران همبازی های مشترکی دارن اما هنوز با هم همبازی نبودن (common neighbours). برای پاسخ به این پرسش ماژولی در gephi وجود نداره. بنابراین از ماژول networkx در زبان پایتون استفاده شده.common=[(e[0], e[1], len(list(nx.common_neighbors(G, e[0],e[1])))) for e in nx.non_edges(G)]
sorted_common = sorted(common, key=lambda x: x[2],reverse=True)
sorted_common[:10]  [(&#039;امین حیایی&#039;, &#039;بهنوش بختیاری&#039;, 19),
 (&#039;امید روحانی&#039;, &#039;جواد عزتی&#039;, 18),
 (&#039;بهنوش بختیاری&#039;, &#039;مهران احمدی&#039;, 18),
 (&#039;مهران رجبی&#039;, &#039;علی صادقی&#039;, 17),
 (&#039;امید روحانی&#039;, &#039;میلاد کی مرام&#039;, 17),
 (&#039;بابک حمیدیان&#039;, &#039;میلاد کی مرام&#039;, 17),
 (&#039;محمدرضا فروتن&#039;, &#039;میلاد کی مرام&#039;, 16),
 (&#039;سحر قریشی&#039;, &#039;رضا رویگری&#039;, 16),
 (&#039;امید روحانی&#039;, &#039;مهران احمدی&#039;, 16),
 (&#039;شقایق فراهانی&#039;, &#039;باران کوثری&#039;, 15)]به این ترتیب 10 تا از بازیگرانی که همچین شرایطی رو داشتن مشخص شدن. مثلا امین حیایی و بهنوش بختیاری 19 همبازی مشترک داشتن در صورتی که هنوز با هم همبازی نبودن.معیار دیگه برای پیش بینی مسیرهای آینده resource allocation هست. این معیار بر اساس میزانی از منابع که از راسی به راس دیگه و از طریق همسایگان مشترک، انتقال پیدا میکنه، محاسبه میشه.برای درک بهتر نحوه محاسبه این شاخص راسهای A,C شکل زیر رو بررسی میکنیممثلا برای محاسبه resource allocation دو راس A و C در شکل بالا به این صورت  عمل میکنیم. از  A تا C دو راس BوD وجود داره. برای راس B یک سوم از مسیرها به C ختم میشه (از مجموع سه مسیر برای B یک مسیر به C میرسه) و همین طور برای راس D یک سوم از مسیرها به C ختم میشه (از مجموع سه مسیر برای D یک مسیر به C میرسه).خروجی محاسبه شده برای شاخص resource allocation :L = list(nx.resource_allocation_index(G))
L.sort(key=operator.itemgetter(2), reverse = True)
L[:10] [(&#039;مهران رجبی&#039;, &#039;علی صادقی&#039;, 0.5436580647280445),
 (&#039;رضا رویگری&#039;, &#039;علی صادقی&#039;, 0.5341189130271286),
 (&#039;سحر قریشی&#039;, &#039;کیمیا باباییان&#039;, 0.5334682225986573),
 (&#039;سحر قریشی&#039;, &#039;یوسف صیادی&#039;, 0.49265883705242974),
 (&#039;مهران رجبی&#039;, &#039;رضا عطاران&#039;, 0.488452442704746),
 (&#039;امین حیایی&#039;, &#039;بهنوش بختیاری&#039;, 0.4703806775218503),
 (&#039;سحر قریشی&#039;, &#039;رضا رویگری&#039;, 0.46925734604593355),
 (&#039;علی صادقی&#039;, &#039;سیروس گرجستانی&#039;, 0.4602600480467179),
 (&#039;ساعد سهیلی&#039;, &#039;بابک حمیدیان&#039;, 0.45217190509044225),
 (&#039;بابک حمیدیان&#039;, &#039;میلاد کی مرام&#039;, 0.45055570910675874)]در مورد link prediction هم روش های زیادی وجود داره مثل:– Jaccard Coefficient– Adamic-Adar Index– Preferential Attachment Scoreاگه تا این قسمت پست ادامه دادین از صبر و حوصلتون برای خوندن این پست نسبتا طولانی تشکر میکنم و امیدوارم براتون مفید باشه :). در بخش بعدی به دسته بندی بر اساس متن معرفی فیلم ها میپردازیم. ایمیل: pooryaganji1368@gmail.comلینکداین: https://www.linkedin.com/in/poorya-ganji-a361a310b/ </description>
                <category>پوریا گنجی</category>
                <author>پوریا گنجی</author>
                <pubDate>Sun, 07 Apr 2019 20:09:36 +0430</pubDate>
            </item>
                    <item>
                <title>نگاهی به داده های مسکن در شهر تهران</title>
                <link>https://virgool.io/dataio/%D9%86%DA%AF%D8%A7%D9%87%DB%8C-%D8%A8%D9%87-%D8%AF%D8%A7%D8%AF%D9%87-%D9%87%D8%A7%DB%8C-%D9%85%D8%B3%DA%A9%D9%86-%D8%AF%D8%B1-%D8%B4%D9%87%D8%B1-%D8%AA%D9%87%D8%B1%D8%A7%D9%86-i47tgtiiolxq</link>
                <description>در این پست نگاهی به داده های مسکن در شهر تهران میندازیم و سعی میکنیم با ابزارهای مختلف تحلیلی روی این داده ها داشته باشیم. برای این کار از بخشی از داده های وبسایت کیلید استفاده میکنیم که خدمات متنوعی در حوزه املاک ارائه میده. این داده ها مربوط به آگهی های فروش املاک مسکونی در مناطق مختلف تهران هست و از تیر تا بهمن سال 97 رو شامل میشه. در بخش اول به تحلیل توصیفی داده ها می پردازیم که بخش مهمی از پروژه های تحلیل داده رو شامل میشه. برای این منظور از نرم افزار معروف شرکت مایکروسافت power bi استفاده میکنیم که طبق گزارش شرکت گارتنر از بهترین ابزارهای حوزه هوش تجاری به حساب میاد.بخش اولپیش نوشت: همون طور که میدونید، خونه های لوکس قیمت های بالایی دارن که خیلی وقتا چند برابر خونه های معمولی قیمت گذاری میشن. به همین دلیل برای توصیف شاخص مرکزی در این گزارش بیشتر از میانه استفاده میکنیم (مثلا میانه قیمت خانه در منطقه 5) چون کمتر از میانگین به مقادیر پرت (outlier) حساسه و کمتر تحت تاثیر این اختلاف ارقام قرار میگیره (میانه به زبان ساده نقطه ای هست که نیمی از داده ها از اون بزرگتر و نیمی دیگه از داده ها از اون کوچک تر هستن مثلا در مورد مجموعه اعداد 1،2،3،5،9 عدد 3 میانه حساب میشه).در ادامه لینک گزارش رو برای دسترسی شما قرار میدم و به بررسی اون میپردازیم.لینک گزارش power biصفحه اول داشبورد شامل سه شکل مختلف و یک فیلتر برای اعمال تغییرات موردنظر میشه که در ادامه به بررسی اونها می پردازیم. مطابق تصویر زیر با انتخاب فیلتر سمت راست میتونیم به لایه های جزیی تر گزارش بریم. کنار فیلتر نمودار میله ای وجود داره که تعداد اگهی ها رو در مناطق مختلف تهران نشون میده که منطقه پنج بیشترین تعداد اگهی ها رو در سایت داشته. اگه روی نمودار کلیک کنیم میتونیم از سال به ماه و سپس روزهای هر ماه بریم. کنار همین نمودار میله ای موقعیت جغرافیایی نمونه ها و اسم محله رو میبینیم. اندازه هر دایره میانگین قیمت هر متر در اون ناحیه رو نشون میده و همون طور که مشخصه مناطق شمالی دایره های بزرگتر و خونه های گرون قیمت تری رو دارن. آخرین شکل در پایین صفحه فیمت ملک نسبت به مساحت دیده میشه و میتونیم ببینیم خونه های مختلف بر حسب مساحت چقدر قیمت گذاری شدن (که البته برای املاکی که کمتر از 500 متر و قیمت کمتر از 5 میلیارد فیلتر شدن).صفحه اول داشبورددر صفحه دوم گزارش که با کلیک در پایین صفحه گزارش انجام میشه سه شکل متفاوت وجود داره. نحوه رفتن به صفحه دومصفحه دوم گزارشدر شکل سمت چپ امکان مقایسه میانگین و میانه قیمت در مناطق مختلف وجود داره. همون طور که قبلا اشاره شد در مورد شاخص های مرکزی میانگین به داده های غیر عادی یا پرت حساس تر هست و هرقدر داده ها به صورت نرمال توزیع شده باشن میانه و میانگین به هم نزدیکترن. در مورد داده های مسکن در مناطقی مثل 1و2و3 میانگین ومیانه فاصله زیادی از هم دارن و نشون میده در اون مناطق خونه های گرون قیمتی نسبت به سایر خونه ها زیادی وجود داره. درحالیکه در مناطقی مثل 9و21و19 این طور نیست.شکل بالا سمت راست، تغییرات قیمت نسبت به زمان رو نشون میده. البته به لطف حالت تعاملی داشبورد میتونیم با کلیک روی منطقه خاصی از شکل های دیگه این تغییرات رو در هر منطقه به صورت حداگانه ببینیمآخرین شکل در این صفحه به مقایسه تغییرات قیمت نسبت به مساحت در مناطق مختلف شهرداری مربوط میشه. بخش دومدر این قسمت از زبان برنامه نویسی پایتون استفاده میکنیم که در سال های اخیر کاربرد وسیعی در مسائل تحلیل داده پیدا کرده. قصد داریم به کمک یکی از پرکاربردترین الگوریتم های یادگیری ماشین یعنی رگرسیون خطی به مدلی ساده از قیمت مسکن که قابلیت پیش بینی داشته باشه برسیم. رگرسیون در ساده ترین حالت مدلیه که از تعدادی متغیر مستقل و یک متغیر وابسته تشکیل شده و هدف پیدا کردن بهترین ضرایب برای متغیرهای مستقل جهت تبیین متغیر وابسته هست.قبل از اینکه داده ها رو بتونیم به عنوان ورودی به مدل بدیم باید داده ها رو اصطلاحا پیش پردازش (preprocessing) کنیم که شامل حذف یا اصلاح داده های کثیف، آماده سازی متغیرها و... میشه. این بخش مهمترین قسمت کاره که تا هشتاد درصد وقت رو به خودش اختصاص میده. ابتدا داده ها رو با پکیج pandas فراخوانی میکنیم. در اینجا 70000 سطر ابتدایی داده ها استفاده شده و سطرهایی که دارای داده گمشده (null) بودن حذف شدن (البته در مواردی لازمه که با روش هایی مثل میانگین گرفتن یا الگوریتم های یادگیری ماشین، این داده ها جایگزین بشن). import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
data=pd.read_csv (&quot;...\kilid.csv&quot;,nrows=70000)
data.dropna(subset=[&#039;region&#039;,&#039;landuseType&#039;,&#039;noBeds&#039;, &#039;floorArea&#039;,&#039;price&#039;],inplace=True)پنج سطر ابتدایی داده هایکی دیگه از مواردی که قبلا اشاره شد وجود داده های غیر طبیعی، نویز یا پرت (outlier) در داده هاست. این موارد غیرطبیعی باعث سردرگمی مدل ما میشن. در این مورد ما ساده ترین رویکرد رو انتخاب میکنیم به این صورت که از 5 درصد ابتدایی و انتهایی داده ها صرف نظر میکنیم (مواردی که قیمت خیلی پایین یا خیلی بالایی دارن از مجموعه حذف میکنیم) سپس متغیر قیمت خانه رو به عنوان متغیر وابسته که قصد پیشبینی مقدار اون رو داریم (y) و سایر متغیرها رو به عنوان متغیر وابسته (x) در نظر میگیریم.P = np.percentile(data[&#039;price&#039;], [5, 95])
new_df = data[(data[&#039;price&#039;] &gt; P[0]) &amp; (data[&#039;price&#039;] &lt; P[1])]
X=new_df[[&#039;landuseType&#039;,&#039;region&#039;,&#039;noBeds&#039;, &#039;floorArea&#039;]].values
y=new_df.price.values.reshape(-1,1)ثالدر مرحله بعد برای آماده سازی متغیرها و اجرای الگوریتم از پکیج sklearn استفاده میکنیم. حالا باید متغیرهایی که غیررتبه ای هستن به متغیرهای رتبه ای تبدیل کنیم. در مورد داده های ما مناطق مختلف شهرداری حالت غیر رتبه ای دارن یعنی مثلا در پیش بینی قیمت ملک فاصله منطقه پنج و شش با فاصله منطقه شش و هفت یک واحد نیست و همین طور فاصله منطقه دوازده از منطقه دو 10 واحد نیست و اعداد صرفا اسم اون منطقه محسوب میشن. در حالی که در مورد متغیر دیگه ( مساحت خانه) فاصله 71 متری از 70 متری مثل 81متری از متری و همین طور 80 متری تا 70 متری دقیقا 10 واحد هست. پس مطابق مثال زیر که اسامی کشورها به ستون های مجزا تبدیل شده، متغیر منطقه شهرداری در مدل ما به ستون های مجزا تقسیم میشه (از یک ستون به 22 ستون برای مناطق 22 گانه) هر چند برای جلوگیری از بروز همخطی چندگانه (multicollinearity) باید یکی از آنها را حذف کنیم.نحوه تبدیل داده های اسمی به عددی(رتبه ای)from sklearn.preprocessing import LabelEncoder, OneHotEncoder
labelencoder = LabelEncoder()
X[:, 0] = labelencoder.fit_transform(X[:, 0])
X[:, 1] = labelencoder.fit_transform(X[:, 1])
onehotencoder = OneHotEncoder(categorical_features = [0,1])
X = onehotencoder.fit_transform(X).toarray()
X = X[:, 1:]اما در مورد مساحت خانه رابطه بین مساحت خانه و قیمت، الزاما یک رابطه خطی نیست (افزایش قیمت به ازای افزایش مساحت از 70 متر به 71متر با افزایش قیمت به ازای افزایش مساحت از 100 به 101 متر یکسان نیست و معمولا خانه های بزرگتر با شیب کمتری گرون میشن). تفاوت رابطه خطی و غیر خطیبرای افزایش انعطاف مدل در این مورد از متغیر درجه دوم(توان دوم مساحت خانه) استفاده میکنیم. from sklearn.preprocessing import PolynomialFeatures
X_poly=PolynomialFeatures().fit_transform(X[:,-1].reshape(-1,1))
X=np.append(X,X_poly,axis=1)در نهایت برای اینکه بتونیم دقت مدلمون رو بسنجیم باید بخشی از داده ها رو به عنوان داده های آموزش (train) جدا کنیم و از اون برای آموزش مدل استفاده کنیم و بخش دیگه رو (test) فقط برای ارزیابی مدل استفاده کنیم (در اینجا 80 درصد آموزش و 20 درصد تست).from sklearn.cross_validation import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)
from sklearn.linear_model import LinearRegression
regressor = LinearRegression()
regressor.fit(X_train, y_train)
y_pred = regressor.predict(X_test)همون طور که مشاهده میکنین شاخص R-squared برای مدل حدود 74 درصد به دست اومده و به این معنیه که قدرت پیش بینی مدل ما 74 درصد و به عبارت علمی تر 74 درصد واریانس موجود در قیمت رو تبیین میکنه.یکی دیگه از معیارهای سنجش صحت مدل، نرمال بودن توزیع خطای مدل(residuals) هست. به این صورت که خطای مدل نسبتا مختصر و دارای توزیع نرمال باشه. از این بابت هم مدل ما وضعیت قابل قبولی دارهشکل زیر کمک میکنه تصویر واضح تری از مدل پیدا کنیم به این صورت که محور افقی مساحت ملک(مترمربع) و محور عمودی قیمت ملک(میلیارد تومان) هستن و اینکه نقطه های آبی موارد ثبت شده و نقاط نارنجی پیشبینی های مدل هستن که همپوشانی قابل قبولی دارن. plt.figure(figsize=(10,5))
plt.scatter(X_test[:,-2:-1],y_test)
plt.scatter(X_test[:,-2:-1],y_pred)
plt.xlabel(&quot;area&quot;)
plt.ylabel(&quot;price&quot;)این مدل صرفا یک مدل ساده و اولیه هست و میتونه با مدل های پیچیده تر رگرسیون مثل lasso و ridge و همین طور سایر رگرسیون ها مثل رگرسیون درخت تصمیم، رگرسیون ماشین بردار پشتیبان، شبکه عصبی و ... بهبود قابل ملاحظه ای پیدا کنه. سعی میکنم دیتاها و مدل رو در github قرار بدم (در صورتی که سایت kilid.com مشکلی با این قضیه نداشته باشه). چون داده ها داخلی و واقعی هستن کار کردن با اونها میتونه جالب باشه. در پایان از وقتی که برای مطالعه گذاشتین ممنونم و منتظر شنیدن نظرات هستمایمیل: pooryaganji1368@gmail.com</description>
                <category>پوریا گنجی</category>
                <author>پوریا گنجی</author>
                <pubDate>Tue, 05 Feb 2019 18:51:01 +0330</pubDate>
            </item>
                    <item>
                <title>داشبورد تحلیل اینستاگرام</title>
                <link>https://virgool.io/@pooryaganji1368/%D8%AF%D8%A7%D8%B4%D8%A8%D9%88%D8%B1%D8%AF-%D8%AA%D8%AD%D9%84%DB%8C%D9%84-%D8%A7%DB%8C%D9%86%D8%B3%D8%AA%D8%A7%DA%AF%D8%B1%D8%A7%D9%85-fqltk3heemje</link>
                <description>اگر به ارزش تحلیل داده های اینستاگرام پیجتون اعتقاد دارین و دوست دارین با یه ابزار ساده در این زمینه آشنا بشین، میتونین مستقیم به بخش دوم نوشته مراجعه کنین. در غیر این صورت شاید خوندن بخش اول کمی نظرتون رو عوض کنه.بخش اولچند سالی هست که اینستاگرام به محبوب ترین شبکه اجتماعی ایرانی ها تبدیل شده (با این فرض که تلگرام پیامرسان هست و شبکه اجتماعی محسوب نمیشه). آمار دقیقی از تعداد کاربرای ایرانی وجود نداره ولی جالبه بدونید کافه بازار بیش از بیست و یک میلیون نصب فعال رو برای اینستاگرام نشون میده. حجم بالای کاربران و جوان بود این جمعیت حوزه جذابی برای فعالیت کسب و کارای مختلف فراهم کرده. از طرفی حجم بالای محتوای تولید شده و رقابت برای دیده شدن باعث شده فعالیت تجاری در فضای آنلاین به یک تخصص و فعالیت حرفه ای تبدیل بشه.  در این دنیای بزرگ دیجیتالی چطور میشه فعالیت هایی انجام داد که مورد پسند جامعه هدف کسب و کار شما باشه؟ یکی از نیازهایی که برای بهینه سازی فعالیتها نیازه تحلیل رفتار کاربران پیج شماست تا اطلاعاتی درباره واکنش اونها به پست ها، هشتک های استفاده شده در پست ها و ... به دست بیارین. در این مورد شرکت اینستاگرام امکاناتی برای پیج های تجاری در نظر گرفته. کافیه درخواست خودتون رو مطرح کنید و از این امکانات به صورت رایگان استفاده کنید. اما بسیاری از مواقع این امکانات برای فعالیت تجاری کافی نیست. شرکت های مختلفی خارج از ایران( ...,socialbakers,socialmediaexaminer,sproutsocial) به وجود اومدن تا این خلا موجود در بازار رو پر کنند اما متاسفانه کاربرای ایرانی با وجود مشکلاتی مثل تحریم، قیمت بالای این خدمات نمیتونن از این سرویس ها استفاده کنن. در ایران هم شرکت ها و افرادی هستن که در این زمینه خدماتی ارائه میدن ولی همچنان شناخته شده نیستند و هنوز جای کار زیادی وجود داره. این مقدمه نسبتا طولانی رو نوشتم تا به بخش دوم برسیم و معرفی ابزار ساده ای که برای اینستاگرام تهیه شده.بخش دوملینک گزارش پیج ایستاگرام سریال شهرزاداین ابزار به کمک نرم افزار شرکت مایکروسافت (power bi) تهیه شده که یکی از ابزارهای قدرتمند در زمینه هوش تجاری و ساخت داشبورد های حرفه ای هست و میتونه برای تحلیل و نمایش انواع داده ها  به کار گرفته بشه. با لینکی در ابتدا و انتهای پست موجوده میتونین به صفحه گزارش اصلی برین و خودتون تمام مراحل رو امتحان کنین. گزارش نمونه ای که در ادامه میبینید مربوط به صفحه سریال پرطرفدار شهرزاد هست که با استقبال خوبی از جانب مخاطباش روبرو شد و دوستانی که در زمینه رسانه فعال هستن فعالیت خوب تیم شهرزاد در اینستاگرام رو عامل موثری در دیده شدن این سریال میدونن. این گزارش به اواخر فعالیت پیج مربوط میشه و شامل تمام پستها به جز هشت پست آخر پیج میشه هرچند امکان آپدیت اطلاعات در صورت نیاز حتی چند بار در روز وجود داره. این گزارش شامل سه صفحه میشه. در هر صفحه تعدادی چارت وجود داره که حالت تعاملی دارن و با انتخاب اونها و کلیک روی اجزای مختلف تغییر میکنن و باعث تغییر سایر چارتها میشن و قابیلت های جالبی رو ارائه میدن. اولین صفحه ای که با اون روبرو میشیم شامل چهار چارت مختلف میشه. چارت 1 مجموع لایکها رو در بازه زمانی انتخابی شما نشون میده. در حالت پیش فرض مجموع تعداد لایک ها رو به صورت سالیانه نمایش میده. مثلا در سال 96 پست های پیج شهرزاد حدود 12 میلیون لایک خورده. با انتخاب هر سال امار جزیی تر نشون داده میشه یعنی به صورت ماهانه و سپس روزانه این حالت اصطلاحا drill down گفته میشه و باعث میشه بتونین به لایه های جزیی تر گزارش هدایت بشین که با فلش های بالا و پایین در بالای هر چارت قابل کنترله. چارت 2 به کمک شکل heatmap رسم شده و میتونه شدت متغیر مورد نظر(در اینجا تعداد کامنت ها) رو نشون بده. در اینجا هر قدر از طیف زرد رنگ به طیف سرمه ای نزدیک میشیم به این معنیه که تعداد کامنت ها بیشتر شده. فقط کافیه که سال مورد نظرمون رو در سمت راست چارت انتخاب کنیم تا نمودار اطلاعات همون سال رو نشون بده. نکته دیگه اینکه مواردی هست که نمودار به شکل مربع سفید رنگ دیده میشه این به این معنیه که اون روز پستی روی پیج قرار نگرفته. مثلا سال 97 روز 3 خرداد پستی رو پیج قرار نگرفته ولی مثلا مربع مربوط به 21 خرداد به رنگ سرمه ای تیره در اومده و بیشترین کامنت در این سال روی پست مربوط به این روز وجود داره. چارت 3 مربوط به اطلاعات پست های قرار گرفته روی پیج هست به این ترتیب که ستون اول عکس هر پست رو نشون میده ستون دوم کپشنی که برای اون پست نوشته شده و ستون سوم تاریخ شمسی مربوط به اون پست رو نمایش میده. همون طور که قبلا اشاره کردم این چارت ها با هم در تعامل دارن. مثلا اگه از چارت 1 فروردین سال 97 رو انتخاب کنیم چارت 3 فقط پست های مربوط به همین ماه و سال رو نشون میده.آخرین چارت مربوط به این صفحه محتوای کامنت ها رو نمایش میده. در حالت پیش فرض تمام کامنتهای همه پست ها رو نشون میده. حالا اگه پست خاصی رو از چارت 3 انتخاب کنیم فقط کامنتهای همون پست رو خواهیم داشت. شاید نیاز باشه روی محتوای کامنتها جستجو انجام بدیم و مثلا بخوایم نظر مخاطبان رو در مورد شخصیت قباد بدونیم. خیلی سادست!!! کافیه کنار علامت ذره بین کلیک کنیم و هر کلمه ای میخوایم تایپ کنیم و روی کامنت ها سرچ کنیم.تا اینجا صفحه اول گزارش رو بررسی کردیم با کلیک روی نوار پایین صفحه میتونیم به صفحه دوم و سوم سر بزنیم. صفحه دوم گزارش روی ایده ابرکلمات یا همون wordcloud برای کامنت ها متمرکز شده. اگه با ابر کلمات اشنایی ندارین باید خدمتتون بگم که ایده این هست که بتونیم تصویری از کلمات پرتکرار در متن داشته باشیم و همین طور از تعداد تکرار اونها ذهنیتی پیدا کنیم که اندازه کلمه میتونه نشونه تعداد تکرار اون کلمه باشه. مثلا تو گزارش ما کلمه (قباد) با 310 بار یکی از کلمات پرتکرار بوده که خیلی از مخاطبان پیج از این کلمه استفاده کردن. البته خیلی از کلمات مفهوم خاصی رو انتقال نمیدن مثل کلمه (به). این کلمه ها رو به عنوان کلمات زاید میتونیم فیلتر کنیم که ممکنه سلیقه ای باشه یا مورد به مورد تفاوت داشته باشه. کنار همین همین ابر کلمات چارت دیگه ای وجود داره که میتونه بر اساس کلمات انتخابی شما متن کامنت ها رو نمایش بده.امیدوارم تا اینجا خسته نشده باشین. به توضیح صفحه سوم گزارش میرسیم. تو این صفحه فقط دو تا فیلتر وجود داره که میتونه به ما نشون بده چقدر در جذب افراد جدید و مشارکت اونها در پیج موفق عمل کردیم مثلا اگر برای فیلتر 1 سال 95 و 96 رو انتخاب کنیم 166166 نفر روی پیج شهرزاد کامنت گذاشتن (البته هر کدوم ممکنه چند بار و به تناوب این کار رو انجام داده باشن) حالا میتونیم مقادیر دیگه ای رو برای فیلتر 2 در نظر بگیریم مثلا از سال 97 ماه های فروردین و اردیبهشت رو هم اضافه کنیم. تو این مدت 169053 نفر مشارکت داشتن و روی پیج کامنت گذاشتن و حدود 3000 نفر اونها کاربران جدید بودن.در نهایت از اینکه برای خوندن این مطلب زمان گذاشتین، ممنونم. خوشحال میشم نظرتون رو بدونم. نکته آخر اینکه تمام قسمتها بسته به نیاز میتونه تغییر کنه. اطلاعات اون اپدیت بشه و هر روز با پست ها و محتوای جدید پیج مورد نظر هماهنگ بشه.اگه خواستن از این ابزار برای پیج خودتون یا سایر منابع اطلاعاتی شرکت مثل داده های فروش و .. استفاده کنین،اگه سوالی دارین و یا علاقه دارین در بهبود و توسعه این ابزار همکاری کنین با من در تماس باشین.ایمیل: pooryaganjij1368@gmail.comلینک گزارش پیج ایستاگرام سریال شهرزاد</description>
                <category>پوریا گنجی</category>
                <author>پوریا گنجی</author>
                <pubDate>Sun, 23 Dec 2018 17:42:29 +0330</pubDate>
            </item>
            </channel>
</rss>