ویرگول
ورودثبت نام
پوریا گنجی
پوریا گنجی
خواندن ۷ دقیقه·۳ سال پیش

مقایسه دو روش مختلف تحلیل آماری (A/B تست)

اگه کار تحلیل داده انجام داده باشید حتما به این مورد برخوردید که برای یک آزمون آماری بخش تئوریک مسئله چالش داشته باشد. مثلا محاسبه فاصله اطمینان برای میانه یک نمونه آماری با توزیع نامشخص. در چنین مواردی علاوه بر نیاز به دانستن تئوری آماری کلاسیک و فرض های درست آماری، محاسبه آنها ممکن است کار سخت و زمان بری باشد. در این موارد، روش جایگزین مدلسازی آماری میتواند بسیار کمک کننده باشد. یک روش جایگزین در این مورد رویکرد آمار محاسباتی (computational statistics) است. این رویکرد که در سال های اخیر و با افزایش توان محاسباتی کامپیوترها مورد توجه بیشتری قرار گرفته بر مبنای اجرای مسائل آماری توسط کامپیوتر شکل گرفته است. تکنیک هایی مثل permutation و bootstrapping واژه های اشناتری هستند که به وسیله این رویکرد پیاده سازی میشوند. برای آشنایی ابتدایی با این روش و کاربرد آن میتوانید از این ویدیو و این مخزن گیت هاب استفاده کنید. ویدیو مربوط به یکی از ارائه ها در کنفرانس scipy سال 2017 توسط نویسنده کتاب های معروف think stats و think Bayes است.

تولید نمونه مصنوعی توسط bootstrapping (منبع)
تولید نمونه مصنوعی توسط bootstrapping (منبع)

معمولا درآمار با این مساله روبرو هستیم که یک یا تعدادی نمونه داریم و قصد داریم از نمونه ها حدس هایی درباره جامعه بزنیم و یا اینکه چقدر مطمئنیم تفاوت مشاهده شده بین نمونه ها تصادفی نیست. یکی از چالش های اصلی کم بودن تعداد نمونه هاست در این موارد کمک گرفتن از bootstrapping میتواند راهگشا باشد و تعداد قابل قبولی نمونه مصنوعی ایجاد کند. این نمونه ها اگه به صورت تصادفی تولید شوند و نمونه اولیه تا حد خوبی نماینده جامعه باشد نتایج جالبی داشته و میتواند با مدلسازی های کلاسیک آماری رقابت کند. در ادامه برای یه مساله A/B تست این دو روش رو با هم مقایسه میکنیم

به صورت خلاصه A/B تست یه روش تست محصول است که در آن کاربران به دو گروه تقسیم میشوند. گروه کنترل که ویژگی پیش فرض قدیمی رو تجربه میکنند و یک گروه آزمایشی که ویژگی جدیدی در محصول مشاهده میکنند. اینکه شرایط طراحی این ویژگی ها چطور باید باشد یا اینکه نمونه گیری به چه صورت انجام شود نیاز به بررسی جداگانه دارد.

بازی cookie cats
بازی cookie cats


برای طرح مساله از یکی از دیتاست های کگل استفاده میکنیم و میتوانید از اینجا دانلود کنید. این دیتاست مربوط به یک بازی موبایل است. تغییر مورد مطالعه در اینجا، تغییر زمان وقفه بین بازی(احتمالا برای نمایش تبلیغ به بازیکن) است. یک گروه در مرحله 30 و گروه دیگر در مرحله 40 بازی دچار وقفه شده و مجبورند برای ادامه بازی مدتی صبر کنند (تبلیغ تماشا کنند). در نظر داریم بررسی کنیم تغییری در بازگشت بازیکن به بازی بعد از 7 روز، در این دو حالت وجود دارد یا خیر.

df=pd.read_csv('cookie_cats.csv') df[['userid','version','retention_7']].head()



userid :کد هربازیکن

version : شامل دو ورژن مختلف مورد تست

retention_7: مقدار باینری شامل بازی یا عدم بازی بازیکن بعد از 7 روز


در این مثال دقیقا مشخص نیست کدام گروه کنترل و کدام گروه آزمایش است. نمونه A را به عنوان نمونه کنترل و نمونه B را به عنوان نمونه آزمایش در نظر میگیریم.

#ورژن A a=df[df['version']=='gate_30'] #ورژن B b=df[df['version']=='gate_40']

برای ورژن A بازی (44700 بازیکن) حدود 19 درصد (8502 بازیکن) بعد از 7 روز هنوز برای بازی کردن به بازی سر زدند

در حالیکه برای ورژن B بازی (45489 بازیکن) حدود 18.2 درصد (8279 بازیکن) بعد از 7 روز هنوز برای بازی کردن به بازی سر زدند

اما ایا این تفاوت از نظر اماری معنی دار است؟ چقدر محتمل است که این تفاوت به صورت تصادفی اتفاق افتاده باشد؟

روش اول:

ابتدا روش کلاسیک t-test برای تست احتمال تصادفی بودن تفاوت مشاهده شده در دو نمونه بررسی میشود. احتمال بازی کردن یا نکردن این بازی از نوع احتمالی با دو پیشامد است و توزیع دو اسمی. در صورت کفایت تعداد نمونه ها np>5 (n تعداد نمونه و p احتمال پیشامد) میتواند با تقریب مناسبی به عنوان توزیع نرمال در نظر گرفته شود.

N_cont = a['retention_7'].count() # تعداد نمونه کنترل N_exp = b['retention_7'].count() # تعداد نمونه آزمایش X_cont = a['retention_7'].sum() # تعداد بازیکنی که برای بازی مجدد برگشته (در گروه کنترل) X_exp = b['retention_7'].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): &quot&quot&quotStores the actual samples.&quot&quot&quot self.sample1 = sample1 self.n1 = len(sample1) self.sample2 = sample2 self.n2 = len(sample2) def resample(self): &quot&quot&quotGenerates a new sample by choosing from the original sample with replacement. &quot&quot&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): &quot&quot&quotComputes a sample statistic using the original sample or a simulated sample. &quot&quot&quot return numpy.mean(samples[0])-numpy.mean(samples[1]) def compute_sampling_distribution(self, iters=1000): &quot&quot&quotSimulates many experiments and collects the resulting sample statistics. &quot&quot&quot stats = [self.sample_stat(self.resample()) for i in range(iters)] return numpy.array(stats) def plot_sampling_distribution(self): &quot&quot&quotPlots the sampling distribution.&quot&quot&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('sample statistic') pyplot.xlim(self.xlim) text(0.03, 0.95, 'CI [%0.4f %0.4f]' % tuple(ci)) text(0.03, 0.85, 'SE %0.4f' % se) pyplot.show() samples=Resampler_diff(a['retention_7'],b['retention_7']) samples.plot_sampling_distribution()


توزیع اختلاف نسبت دو ورژن A و B توسط نمونه های مصنوعی ایجاد شده
توزیع اختلاف نسبت دو ورژن 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


a b تستتوسعه محصولآمارتحلیل داده
علاقه مند به تحلیل داده. لینکدین:https://www.linkedin.com/in/pooryaganji
شاید از این پست‌ها خوشتان بیاید