背景:
运营部要对沉默用户进行电话召回,为了探索更高效的召回方式,分别进行了下述两种测试:
1、人工拨打电话
2、AI外呼平台拨打电话
(因方式2需要提前设定机器人的话术,本次测试中设定了两套销售话术,"话术A"和"话术B")
因此,我们要将用户名单分为三组,即:
1、人工组
2、AI话术A组
3、AI话术B组
分别对三组用户进行电话拨打,并在测试后考核接听率和成交率。
问题:
运营同事按时间范围圈选了一部分用户名单,发现名单中的用户在沉默之前分别来自于不同的流量渠道并且有些用户有参加过我们的某个活动,这两个属性("渠道属性"、"是否参与过活动")对本次测试的接听率和成交率都会产生较大的影响。
所以本次需要我们数据组解决的问题是:在考虑用户属性相同的前提下,如何均匀的切分成三个样本?(即,保证三个样本内的用户属性基本一致)
解决:
要解决上述问题,最简单的办法就是随机分组:
即,每个用户被等概率的随机分配到三个实验组当中。
这里我们可以使用机器学习模块中的拆分训练集和测试集的方法:
即,sklearn.model_selection 中的 train_test_split
在python中使用:
from sklearn.model_selection import train_test_split
分别设定训练集和测试集的切分比例进行切分,
train_date, test_date = train_test_split(df_date, train_size=0.5, test_size=0.5, random_state=123)
train_date:我们希望得到的训练集样本
test_date:我们希望得到的测试集样本
df_date:总样本
train_size、test_size:训练集/测试集切分比例
random_state:随机种子(设置某个数字,可保证随机种子相同时我们每次随机切分的结果也相同)
这样可以切成两份,那么三份如何切?
答案很简单,我们只需要对训练集或测试集再切分一次,就是三份了。
具体实现:
满足运营同事的三个小需求:
1、首先观察圈选总样本的用户属性构成是否满足我们的测试需要
2、将圈选总样本切成3份用户属性一样的测试样本
3、对比切分后3个样本的用户属性构成是否一致
样本:
运营同事圈选的总样本
代码:
导入模块/读取数据:
import pandas as pd
from sklearn.model_selection import train_test_split
df = pd.read_excel('圈选总样本.xlsx')
需求1代码:
按维度(一维或多维)分组对某列聚合后查看其非空数量的占比;并可重复查看
例如:以是否参加过活动为分组聚合,查看是否参加过活动的用户占比
def analysis(df):
print(df.info())
y = input('是否查看样本特征占比(y-查看,n-不查看): ')
if y == 'y':
while True:
re_check = 1
while re_check == 1:
group_columns = input('输入分组列名(若多维分组则用逗号间隔输入列名):').split(',')
target_columns = input('输入聚合列名(若多个则用逗号间隔): ').split(',')
for column in group_columns+target_columns:
if column not in list(df):
print('列名输入错误:{}'.format(column))
re_check = 1
break
else:
re_check = 0
grouped = df.groupby(by=group_columns).count()
rate_columns = []
for target_column in target_columns:
rate_name = 'rate_'+target_column
rate_columns.append(rate_name)
col_sum = grouped[target_column].sum()
grouped[rate_name] = grouped.apply(lambda x: str(round((x[target_column]/col_sum)*100, 2))+'%', axis=1)
print(grouped[target_columns+rate_columns])
check_again = input('是否继续查看其他(y-查看,n-不查看): ')
if check_again == 'y':
continue
else:
break
else:
pass
假如,我们要查看总样本的渠道构成,那么输入和输出:
需求2:设定比例均匀切分样本
def sample_cut(df):
sample = df
while True:
n = input('输入切分样本比例(逗号间隔,例如:0.2,0.3,0.5): ')
sizelist = list(map(float, n.split(',')))
if sum(sizelist) != 1:
print('样本切分比例之和不为1')
else:
break
cut_result = []
for i in range(len(sizelist)-1):
cut_size = sizelist[i]/sum(sizelist[i:len(sizelist)])
cut_sample, sample = train_test_split(sample, train_size=cut_size, test_size=1.0-cut_size, random_state=123)
cut_sample.to_excel('样本'+str(i+1)+'切分比例'+str(sizelist[i])+'数量'+str(cut_sample.shape[0])+'.xlsx', index=False)
print('样本'+str(i+1)+' 切分比例:' + str(sizelist[i]) + ' 数量:' + str(cut_sample.shape[0]))
cut_result.append(cut_sample)
sample.to_excel('样本'+str(len(sizelist))+'切分比例'+str(sizelist[-1])+'数量'+str(sample.shape[0])+'.xlsx', index=False)
print('样本'+str(len(sizelist))+' 切分比例:' + str(sizelist[-1]) + ' 数量:' + str(sample.shape[0]))
cut_result.append(sample)
return cut_result
假如我要切三份:可以输入 0.3,0.3,0.4 (注意比例之和为1)
需求3:对比验证切分后的样本是否均匀
def comparison(cut_result):
while True:
re_check = 1
while re_check == 1:
comp_cols = input('输入待对比的分组列名及聚合列名,逗号间隔(例如:is_attend,user_id): ').split(',')
for comp_col in comp_cols:
if comp_col not in list(cut_result[0]):
print('列名输入错误:{}'.format(comp_col))
re_check = 1
break
else:
re_check = 0
comp_dfs = []
rate_columns = []
for i in range(len(cut_result)):
grouped = cut_result[i].groupby(by=[comp_cols[0]]).count()
target_sum = grouped[comp_cols[1]].sum()
rate_colname = 'rate_样本'+str(i+1)
rate_columns.append(rate_colname)
grouped[rate_colname] = grouped.apply(lambda x: str(round(x[comp_cols[1]]/target_sum*100, 2))+'%', axis=1)
comp_dfs.append(grouped)
num = 0
for com_df in comp_dfs:
if num == 0:
df_temp = com_df
num = 1
else:
df_temp = pd.merge(df_temp, com_df, how='left', on=comp_cols[0])
print(df_temp[rate_columns])
re = input('是否继续查看(y-继续,n-结束): ')
if re != 'y':
break
else:
continue
假如,验证渠道属性是否均匀
输入格式:"分组列名,聚合列名"
执行
#待切分样本文件路径
df = pd.read_excel('圈选总样本.xlsx')
#查看待切分样本特征占比
analysis(df)
#按设定比例随机切分成多份样本
cut_result = sample_cut(df)
#对比切分后样本特征占比
comparison(cut_result)