-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.py
More file actions
109 lines (93 loc) · 4.05 KB
/
app.py
File metadata and controls
109 lines (93 loc) · 4.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
from flask import Flask, render_template_string, request
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
import io
import base64
from datetime import datetime
app = Flask(__name__)
# 解决中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
HTML = '''
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>AB测试模拟平台</title></head><body>
<h1>AB测试模拟平台(增长运营专用)</h1>
<form method="post">
样本量: <input name="n_users" value="5000" type="number"><br>
A组基线转化率: <input name="baseline" value="0.10" step="0.01"><br>
B组目标转化率: <input name="b_conv" value="0.127" step="0.01"><br>
每次转化收入(元): <input name="rev" value="100" type="number"><br>
每用户成本(元): <input name="cost" value="5" type="number"><br>
<input type="submit" value="🚀 运行实验">
</form>
{% if results %}
<h2>实验结果({{ date }})</h2>
<p>转化率提升: <strong>{{ conv_lift }}%</strong></p>
<p>ROI提升: <strong>{{ roi_lift }}%</strong></p>
<p>p-value: {{ p_value }}(显著!)</p>
<img src="data:image/png;base64,{{ img1 }}" width="600"><br>
<img src="data:image/png;base64,{{ img2 }}" width="600"><br>
<img src="data:image/png;base64,{{ img3 }}" width="600">
{% endif %}
</body></html>
'''
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
n = int(request.form['n_users'])
baseline = float(request.form['baseline'])
b_conv = float(request.form['b_conv'])
rev = float(request.form['rev'])
cost = float(request.form['cost'])
np.random.seed(42)
group_A = np.random.binomial(1, baseline, n // 2)
group_B = np.random.binomial(1, b_conv, n // 2)
conv_A = np.mean(group_A)
conv_B = np.mean(group_B)
conv_lift = round((conv_B - conv_A) / conv_A * 100, 1)
rev_A = np.sum(group_A) * rev
cost_A = (n // 2) * cost
roi_A = round((rev_A - cost_A) / cost_A * 100, 1)
rev_B = np.sum(group_B) * rev
cost_B = (n // 2) * cost
roi_B = round((rev_B - cost_B) / cost_B * 100, 1)
roi_lift = round((roi_B - roi_A) / roi_A * 100, 1)
_, p_value = stats.ttest_ind(group_A, group_B)
# 生成3张图并转base64
def fig_to_base64(fig):
buf = io.BytesIO()
fig.savefig(buf, format='png', dpi=300, bbox_inches='tight')
buf.seek(0)
return base64.b64encode(buf.read()).decode()
# 图1 转化率
fig1, ax1 = plt.subplots(figsize=(8, 5))
ax1.bar(['Group A', 'Group B'], [conv_A, conv_B], color=['#1f77b4', '#ff7f0e'])
ax1.set_title('转化率对比')
ax1.set_ylabel('转化率')
ax1.bar_label(ax1.containers[0], fmt='%.1f%%', padding=5)
img1 = fig_to_base64(fig1)
plt.close(fig1)
# 图2 分布
fig2, ax2 = plt.subplots(figsize=(8, 5))
ax2.hist(group_A, alpha=0.7, label='Group A', bins=2)
ax2.hist(group_B, alpha=0.7, label='Group B', bins=2)
ax2.set_title('用户转化分布')
ax2.legend()
img2 = fig_to_base64(fig2)
plt.close(fig2)
# 图3 ROI
fig3, ax3 = plt.subplots(figsize=(8, 5))
ax3.bar(['Group A', 'Group B'], [roi_A, roi_B], color=['#1f77b4', '#ff7f0e'])
ax3.set_title('ROI对比')
ax3.set_ylabel('ROI %')
ax3.bar_label(ax3.containers[0], fmt='%.1f%%', padding=5)
img3 = fig_to_base64(fig3)
plt.close(fig3)
return render_template_string(HTML, results=True, conv_lift=conv_lift, roi_lift=roi_lift,
p_value=round(p_value, 4), date=datetime.now().strftime('%Y-%m-%d'),
img1=img1, img2=img2, img3=img3)
return render_template_string(HTML)
if __name__ == '__main__':
print("浏览器打开 http://127.0.0.1:5000")
app.run(debug=True)