项目背景:
有购房或者租房需求的高质量意向客户,在未成交(需求未释放)的情况下,应尽快分配给zy业务员促成成交,否则就很可能会流失,跑到行家(竞争对手)那里成交。
我在该项目做了哪些:
结果数据(最终的意向客户表)是我个人做出来的,流程包括:SQL取数---指标规划---利用excel对数据预处理----利用python进行数据清洗、建模----最终生成结果表。
意向表的产出逻辑:
主要逻辑是运用RFM模型,取用户在中原网的浏览、来电(400电话和直聊)数据,从每个用户的众多浏览和来电房源里从多个房源属性挖掘出意向度最高的房源(判断标准:浏览次数和来电最多),并对用户进行价值分层,高价值用户优先分配和跟进。
用户A | 意向房源 | 意向小区 (列举出3到5个) | 意向价格 区间 | 意向面积 区间 | 最后一次来电房源 |
项目成果:
每两月做一次高意向客户分配表,每次都会有成交,业绩达几十w.
------以下是该项目的完整代码:
# -*- coding: utf-8 -*- """ Created on Wed Jun 19 15:43:37 2019 @author: zhanggl21 """ '''---------------取最近一个月的登录用户浏览报表------------------ ''' #定义最近一个月的起始日期和结束日期 import datetime noww=datetime.datetime.now() end_day=datetime.date(noww.year,noww.month,noww.day) first_day_month=end_day-datetime.timedelta(days=105) #查看有哪些登录用户浏览报表 #import os #os.listdir(r'E:\暂存\登录用户量化表20190114\简化版') #取最近一个月浏览数据表 import pandas as pd df1=pd.read_excel('E:\\暂存\\客户分配\\第三批客户分配\\' '2019年(9.1-9.30)登录用户行为报表.xlsx') #将浏览表里“浦东”统一替换为“浦东新区” df1.区域.replace({'浦东':'浦东新区'},inplace=True) #将日期升序排列,便于后面索引 df1.sort_values(by='操作日期',ascending=True,inplace=True) #visit_df=df1.set_index('操作日期')[str(first_day_month):str(end_day)] visit_df=df1.set_index('操作日期') #排除价格为0的记录 visit_df=visit_df[visit_df.价格>0] #增加“预算”和“面积分布”字段 visit_df['预算']=pd.cut(visit_df.价格,\ bins=[0,2000,3000,5000,8000,12000,\ visit_df[(visit_df.租售类型=='租房')].价格.max(),1500000,2000000,\ 2500000,3500000,5000000,7000000,10000000,10000000000],\ labels=['2000元以下','2000元-3000元','3000元-5000元','5000元-8000元',\ '8000元-12000元','12000元以上','150万以下','150万-200万',\ '200万-250万','250万-350万','350万-500万','500万-700万',\ '700万-1000万','1000万以上']) visit_df['面积分布']=pd.cut(visit_df.面积, bins=[0,50,70,90,110,130,150,visit_df.面积.max()], labels=['50平以下','50平-70平','70平-90平','90平-110平', '110平-130平','130平-150平','150平以上']) #把5室以上的户型统一命名为'6室以上' visit_df.户型[visit_df.户型.str.contains('[6-9]室|1[0-9]室|2[0-9]室',regex=True)]='6室及以上' visit_df.户型[visit_df.户型.str.contains('[0-5]室',regex=True)]=visit_df.户型.str[0:2] visit_df=visit_df[['用户ID','小区','租售类型','区域','板块','户型',\ '预算','面积分布']].drop_duplicates() #把“租售类型”的值统一修改为“买卖”与“租赁” visit_df.租售类型.replace({'二手房':'买卖','租房':'租赁'},inplace=True) #修改列名 visit_df=visit_df.reset_index() visit_df.rename(columns={'用户ID':'用户id','小区':'小区名称',\ '区域':'房源所在区域','板块':'房源所在板块',\ '户型':'房源户型','预算':'房源预算',\ '面积分布':'面积'},inplace=True) #用户id统一小写 visit_df.用户id=visit_df.用户id.str.lower() #用户id去除空格 visit_df.用户id=visit_df.用户id.str.strip() #将用户id与板块组成新列“用户id与板块” visit_df['用户id与板块']=visit_df.用户id+visit_df.房源所在板块 #先确定每个用户浏览最多的板块,求用户id对应最多的板块 from scipy import stats func_m1=lambda x:stats.mode(x)[0][0] user_liulan_bk=visit_df.groupby('用户id').agg({'房源所在板块':func_m1}) user_liulan_bk=user_liulan_bk.reset_index() user_liulan_bk['用户id与板块']=user_liulan_bk.用户id+user_liulan_bk.房源所在板块 #以每个用户访问最多的板块为基准进一步以此合并其它维度 visit_df_most=pd.merge(left=user_liulan_bk.drop(['用户id','房源所在板块'],axis=1),right=visit_df,\ how='left',left_on='用户id与板块',\ right_on='用户id与板块') #匹配用户所访问楼盘的小战区 zhanqu_df=pd.read_excel(r'E:\lele月工作记录\楼盘与黄金展位业务员与摊20190805.xlsx',\ sheet_name='楼盘对应的小战区') visit_df_zq=pd.merge(left=visit_df_most,\ right=zhanqu_df[['楼盘','小战区','小战区ID']].drop_duplicates(),\ how='left',left_on='小区名称',right_on='楼盘') #排序,以便每个用户对应的小战区(非空)在最前 visit_df_zq=visit_df_zq.sort_values(by=['用户id','小战区','小区名称'],\ ascending=[True,False,True]) #拼接每个用户id的浏览小区名称(只保留3个浏览小区) #def collect_set(group): # return set(group.values) #def collect_tuple(group): # return tuple(group.values[0:3]) def collect_str(group): return str(','.join(map(str,list(set([x for x in group.values[0:3]]))))) def collect_zq(group): return group.values[0] visit_df_xq=visit_df_zq[['用户id','小区名称','小战区ID','小战区']].drop_duplicates().\ groupby('用户id').agg({'小区名称':collect_str,'小战区ID':collect_zq,'小战区':collect_zq}) #返回每个用户id对应浏览最多的区域、板块、户型、预算 #visit_df_other=visit_df_most.groupby('用户id').agg({'房源所在区域':func_m1, # '房源所在板块':func_m1, # '房源户型':func_m1, # '房源预算':func_m1, # '租售类型':func_m1, # '面积':func_m1}) visit_df_other=visit_df_most.groupby('用户id').agg({'房源所在区域':func_m1, '房源所在板块':func_m1, '房源预算':func_m1, '面积':func_m1}) #根据预算来判断租售类型(新建一列,不用原表里的) visit_df_other['租售类型']=['买卖' if '万' in x else '租赁' for x in visit_df_other.房源预算] #根据面积来判断房源户型(新建一列,不用原表里的) import random lst1=[] for x in visit_df_other.面积: if x in ['50平以下']: lst1.append('1室') elif x in ['50平-70平','70平-90平']: lst1.append('2室') elif x in ['90平-110平','110平-130平','130平-150平']: lst1.append(random.choice(['4室','3室'])) elif x in ['110平-130平','130平-150平']: lst1.append(random.choice(['3室','4室'])) elif x in ['150平以上']: lst1.append(random.choice(['3室','4室','5室','6室及以上'])) visit_df_other['房源户型']=lst1 #合并最终的浏览表并增加新列“分类” visit_df_last=pd.merge(left=visit_df_xq,right=visit_df_other,how='outer', left_on='用户id',right_on='用户id') visit_df_last['分类']='浏览' '''---------------注册用户报表------------------ ''' zc_df=pd.read_excel(r'E:\暂存\客户分配\第三批客户分配\2019年(9.1-9.30)注册.xlsx') register_df=zc_df[['注册时间','用户ID','手机号']].drop_duplicates() '''---------------取最近一个月的直聊报表------------------ ''' #查看文件列表 #os.listdir(r'E:\暂存\客户分配') #导入直聊数据 zl_df=pd.read_excel(r'E:\暂存\客户分配\第三批客户分配\2019年(9.1-9.30)直聊.xlsx') #zl_df=pd.concat([df1,df2],join='outer',ignore_index=False) #取最近一个月直聊数据表 zl_df=zl_df[['序号','发送消息时间','用户id','手机号','楼盘名称','租售类型',\ '价格','面积','户型']].drop_duplicates().\ set_index('发送消息时间') #增加"预算"列 zl_df['预算']=pd.cut(zl_df.价格, bins=[0,2000,3000,5000,8000,12000, zl_df[zl_df.租售类型=='买卖'].价格.min(),1500000,2000000, 2500000,3500000,5000000,7000000,10000000,10000000000], labels=['2000元以下','2000元-3000元','3000元-5000元','5000元-8000元', '8000元-12000元','12000元以上' +str(zl_df[zl_df.租售类型=='买卖'].价格.min()/10000) +'万以下','150万以下','150万-200万', '200万-250万','250万-350万','350万-500万','500万-700万', '700万-1000万','1000万以上'],right=False) #增加"面积分布"列 zl_df['面积分布']=pd.cut(zl_df.面积, bins=[0,50,70,90,110,130,150,zl_df.面积.max()], labels=['50平以下','50平-70平','70平-90平','90平-110平', '110平-130平','130平-150平','150平以上']) #与房源匹配表聚合以匹配区域与板块 fy_df=pd.read_excel(r'E:\lele月工作记录\数据匹配与高级筛选201712updated.xlsx', sheet_name='中原网房源明细') zl_df_h=pd.merge(left=zl_df,right=fy_df[['楼盘名称','行政区','片区']].\ drop_duplicates(),how='inner',left_on='楼盘名称',\ right_on='楼盘名称') #只要需要的列 zl_df_h=zl_df_h[['用户id','手机号','楼盘名称','行政区','片区','租售类型', '面积分布','户型','预算']].drop_duplicates() #增加新列“用户id与片区与租售类型” zl_df_h['用户id与片区与租售类型']=zl_df_h.用户id+zl_df_h.片区+zl_df_h.租售类型 #先取每个用户的板块和租售类型(以最多来确定) zhiliao_df_bk=zl_df_h.groupby(by='用户id').agg({'用户id与片区与租售类型':func_m1}) #进一步以此合并其它维度 zl_df_f=pd.merge(left=zhiliao_df_bk['用户id与片区与租售类型'], right=zl_df_h,how='left', left_on='用户id与片区与租售类型', right_on='用户id与片区与租售类型') zl_df_zq=pd.merge(left=zl_df_f,\ right=zhanqu_df[['楼盘','小战区','小战区ID']].drop_duplicates(),\ how='left',left_on='楼盘名称',right_on='楼盘') #排序,以便每个用户对应的小战区(非空)在最前 zl_df_zq=zl_df_zq.sort_values(by=['用户id','小战区','楼盘名称'],\ ascending=[True,True,True]) #以此进一步取其它字段出现最多的值 zl_df_other=zl_df_f.groupby('用户id').agg({'行政区':func_m1, '片区':func_m1, '租售类型':func_m1, '面积分布':func_m1, '户型':func_m1, '预算':func_m1, '手机号':func_m1}) #为每个用户id拼接小区名称 zl_df_xq=zl_df_zq[['用户id','楼盘名称','小战区ID','小战区']].drop_duplicates().\ groupby('用户id').agg({'楼盘名称':collect_str,'小战区ID':collect_zq,'小战区':collect_zq}) #合并最终的直聊表并增加新列“分类” zl_df_last=pd.merge(left=zl_df_other,right=zl_df_xq,how='inner', left_on='用户id',right_on='用户id') zl_df_last['分类']='直聊' '''---------------取最近一个月的电话报表------------------ ''' call_df=pd.read_excel(r'E:\暂存\客户分配\第三批客户分配\2019年(9.1-9.30)400来电.xlsx') #取最近一个月的电话表(屏蔽掉房源面积为空的记录) call_df=call_df.set_index('被叫时间') #删除房源面积为空的记录(即只保留房源来电,网营及经纪频道等来电都排除) call_df=call_df[['ID','房源信息','房源面积','租售类型','预算', '客户信息']].drop_duplicates().dropna(subset=['房源面积']) call_df.rename(columns={'房源信息':'楼盘名称'},inplace=True) #导入房源匹配表以匹配区域、板块 call_df_h=pd.merge(left=call_df, right=fy_df[['楼盘名称','行政区','片区']].drop_duplicates(), how='inner',left_on='楼盘名称',right_on='楼盘名称') #删除空值及没有价格的记录 call_df_h.dropna(subset=['预算'],inplace=True) call_df_h=call_df_h[~call_df_h.预算.isin(['无'])] #增加面积与价格的分布 call_df_h['预算分布']=pd.cut(call_df_h.预算, bins=[0,2000,3000,5000,8000,12000, call_df_h[call_df_h.租售类型=='买卖'].预算.min(),1500000,2000000, 2500000,3500000,5000000,7000000,10000000,10000000000], labels=['2000元以下','2000元-3000元','3000元-5000元','5000元-8000元', '8000元-12000元','12000元以上' +str(call_df_h[call_df_h.租售类型=='买卖'].预算.min()/10000) +'万以下','150万以下','150万-200万', '200万-250万','250万-350万','350万-500万','500万-700万', '700万-1000万','1000万以上'],right=False) call_df_h['面积分布']=pd.cut(call_df_h.房源面积, bins=[0,50,70,90,110,130,150,call_df_h.房源面积.max()], labels=['50平以下','50平-70平','70平-90平','90平-110平', '110平-130平','130平-150平','150平以上']) call_df_f=call_df_h[['ID','楼盘名称','租售类型','客户信息','行政区','片区', '预算分布','面积分布']].drop_duplicates() #增加新列“客户信息与片区与租售类型” call_df_f['客户信息与片区与租售类型']=call_df_f.客户信息.\ astype('str')+call_df_f.片区+call_df_f.租售类型 #先取每个用户的板块和租售类型(最多) call_df_bk=call_df_f.groupby('客户信息').agg({'客户信息与片区与租售类型':func_m1}) call_df_bk=call_df_bk.reset_index() #进一步以此合并其它维度 call_df_m=pd.merge(left=call_df_bk['客户信息与片区与租售类型'], right=call_df_f,how='left', left_on='客户信息与片区与租售类型', right_on='客户信息与片区与租售类型') #匹配出小战区 call_df_zq=pd.merge(left=call_df_m,\ right=zhanqu_df[['楼盘','小战区','小战区ID']].drop_duplicates(),\ how='left',left_on='楼盘名称',right_on='楼盘') #排序,以便每个用户对应的小战区(非空)在最前 call_df_zq=call_df_zq.sort_values(by=['客户信息','小战区','楼盘名称'],\ ascending=[True,True,True]) #取每个用户最多的租售类型、客户信息、行政区、片区、预算分布、面积分布 call_df_other=call_df_m.groupby('客户信息').agg({'租售类型':func_m1, '行政区':func_m1, '片区':func_m1, '预算分布':func_m1, '面积分布':func_m1}) #拼接每个用户浏览的小区名称、并选取其中一个小战区 call_df_xq=call_df_zq[['客户信息','楼盘名称','小战区ID','小战区']].drop_duplicates().\ groupby('客户信息').agg({'楼盘名称':collect_str,'小战区ID':collect_zq,'小战区':collect_zq}) #合并最终的电话表并添加分类 call_df_last=pd.merge(left=call_df_other,right=call_df_xq,how='outer', left_on='客户信息',right_on='客户信息') #根据面积来判断房源户型(原电话明细表里没有户型,也房源id从而也无法匹配) import random lst_hx=[] for x in call_df_last.面积分布: if x in ['50平以下']: lst_hx.append('1室') elif x in ['50平-70平','70平-90平']: lst_hx.append('2室') elif x in ['90平-110平','110平-130平','130平-150平']: lst_hx.append(random.choice(['4室','3室'])) elif x in ['110平-130平','130平-150平']: lst_hx.append(random.choice(['3室','4室'])) elif x in ['150平以上']: lst_hx.append(random.choice(['3室','4室','5室','6室及以上'])) call_df_last['房源户型']=lst_hx call_df_last['分类']='电话' '''---------------合并各个表------------------ ''' #完善电话表 call_df_last=call_df_last.reset_index() call_df_last.rename(columns={'行政区':'区域','客户信息':'手机号', '片区':'板块','面积分布':'面积', '预算分布':'预算','房源户型':'户型'},inplace=True) #完善直聊表 zl_df_last=zl_df_last.reset_index() zl_df_last.rename(columns={'行政区':'区域','片区':'板块', '面积分布':'面积'},inplace=True) #完善浏览表 visit_df_last=visit_df_last.reset_index() visit_df_last.rename(columns={'小区名称':'楼盘名称', '房源所在区域':'区域', '房源所在板块':'板块', '房源户型':'户型', '房源预算':'预算'},inplace=True) #完善注册表 register_df.rename(columns={'用户ID':'用户id'},inplace=True) register_df.用户id=register_df.用户id.str.lower() #给浏览电话表同一个用户id匹配上电话号码(原浏览明细表有用户id但电话号码都为空) visit_df_lastl=pd.merge(left=visit_df_last,\ right=register_df[['用户id','手机号']].\ dropna(subset=['手机号']),\ how='left',on='用户id') #合并电话、直聊、浏览表 call_zhiliao_liulan=pd.concat([visit_df_lastl,call_df_last,zl_df_last],join='outer') #注册与浏览直聊合并 df_last1=pd.merge(left=register_df.drop_duplicates(), right=call_zhiliao_liulan [(call_zhiliao_liulan.分类=='浏览') |(call_zhiliao_liulan.分类=='直聊')].drop(['手机号'],axis=1), how='left',left_on='用户id',right_on='用户id') #删掉手机号为空的记录 df_last1.dropna(subset=['手机号'],inplace=True) #匹配到的浏览直聊用户id lst_liulan_zl=df_last1[df_last1.分类.notnull()].用户id.unique() #注册与电话合并 df_last2=pd.merge(left=register_df, right=call_zhiliao_liulan[call_zhiliao_liulan.分类=='电话']. drop(['用户id'],axis=1), how='left',left_on='手机号',right_on='手机号') #删掉手机号为空的记录 df_last2.dropna(subset=['手机号'],inplace=True) lst_dh=df_last2[df_last2.分类.notnull()].用户id.unique() #合并最终结果表 df_last=pd.concat([df_last1,df_last2],join='outer',keys=['用户id','用户id'], ignore_index=True) #单独注册的记录(即未匹配到电话、直聊、浏览) df_zc=df_last[~(df_last.用户id.isin(list(lst_liulan_zl)+list(lst_dh)))].drop_duplicates() #浏览直聊电话记录 df_liulan_dh_zl=df_last[df_last.分类.isin(['直聊','浏览','电话'])].drop_duplicates() df_last=pd.concat([df_liulan_dh_zl,df_zc],join='outer').sort_values(by=['用户id']) #把预算和面积列的值转换为str,方便后面去重,因为list,ndarray,set均无法哈希 df_last.预算=df_last.预算.astype('str') df_last.面积=df_last.面积.astype('str') df_last.面积=df_last.面积.replace('nan','') df_last.预算=df_last.预算.replace('nan','') #去重 df_last.drop_duplicates(inplace=True) #以用户id为主键排序 df_last.sort_values(by='用户id',inplace=True) #调整列位置 order=['注册时间','用户id','手机号','楼盘名称','区域','板块','面积','户型', '预算','租售类型','分类','小战区ID','小战区'] #待匹配摊前的结果表 df_last=df_last[order] '''-------------匹配与楼盘对应的学校和地铁-----------------------''' lp_lst=[] for x in df_last.楼盘名称: if x is None: lp_lst.append(x) elif str(x).find(',')==-1: lp_lst.append(x) else: lp_lst.append(str(x).split(',')[0]) df_last['第一个楼盘']=lp_lst df_last.rename(columns={'第一个楼盘':'楼盘'},inplace=True) ##导入小战区匹配表(每个楼盘只取一个摊) #tan_df=pd.read_excel(r'E:lele月工作记录楼盘与黄金展位业务员与摊20190805.xlsx') #tan_df=tan_df.groupby('楼盘').head(1) # ##匹配小战区 #result_df=pd.merge(left=df_last, # right=tan_df[['楼盘','小战区','小战区ID','大战区']].drop_duplicates(), # how='left',left_on='楼盘',right_on='楼盘') #匹配楼盘周边的地铁与学校 import pandas as pd lp_r_s=pd.read_excel(r'E:\lele月工作记录\中原网楼盘周边地铁及学校20190809.xlsx') lp_r_s.rename(columns={'楼盘名称':'楼盘'},inplace=True) result_df_final=pd.merge(left=df_last, right=lp_r_s[['楼盘', '地铁站', '地铁线路', '学校']], how='left',left_on='楼盘',right_on='楼盘') #去重并导出最终结果表 result_df_final=result_df_final[['注册时间', '用户id', '手机号', '楼盘名称', '区域','板块', '面积', '户型', '预算', '租售类型','地铁站', '地铁线路', '学校', '分类','小战区ID', '小战区']].drop_duplicates() #统一板块名称 result_df_final.板块=result_df_final.板块.str.replace('片区','') #导出结果表 result_df_final.to_excel(r'd:\Users\zhanggl21\Desktop\秒客客户分配表'+str(end_day)+'.xlsx',index=False)