标签:输入参数 限制 更新 空间换时间 最大的 今天 fat 指标 nic
1. SQL题目
题目:有一张用户签到表【t_user_attendence】,标记每天用户是否签到(说明:该表包含所有用户所有工作日的出勤记录) ,包含三个字段:日期【fdate】,用户id【fuser_id】,用户当天是否签到【fis_sign_in:0否1是】;
问题1:请计算截至当前每个用户已经连续签到的天数(输出表仅包含当天签到的所有用户,计算其连续签到天数)
输出表【t_user_consecutive_days】:用户id【fuser_id】,用户联系签到天数【fconsecutive_days】
解答逻辑非常简单,只需要用max和datediff。
问题1答案: 思路:先找用户最近一次未签到日期,再用今天减那个日期 create table t_user_consecutive_days as select fuser_id ,datediff(‘20200322‘,fdate_max) fconsecutive_days from (select fuser_id ,max(fdate) fdate_max from t_user_attendence where fis_sign_in = 0 group by fuser_id ) t1 ;
问题1修改: 思路:我觉得还得限制用户是今天的。 create table t_user_consecutive_days as select fuser_id ,datediff(‘20200322‘,fdate_max) fconsecutive_days from (select fuser_id ,max(fdate) fdate_max from t_user_attendence where fis_sign_in = 0 group by fuser_id ) t1 where fuser_id in ( select fuser_id from t_user_attendence where fdate = ‘20200322‘) ;
问题2:请计算每个用户历史以来最大的连续签到天数(输出表为用户签到表中所有出现过的用户,计算其历史最大连续签到天数)
输出表【t_user_max_days】:用户id【fuser_id】,用户最大连续签到天数【fmax_days】
1 问题2答案:把用户所有签到记录转化成一条0-1字符串序列,用0做split切割,计算切出来的1序列组中的最大长度 2 3 create table t_user_max_days as 4 select fuser_id 5 ,max(length(cut_fsign_record)) as fmax_days 6 (select fuser_id 7 ,fsign_record 8 ,cut_fsign_record 9 from 10 (select fuser_id 11 ,wm_concat(fis_sign_in) fsign_record 12 from t_user_attendence 13 group by fuser_id 14 ) t1 15 lateral view explode(split(fsign_record,‘0‘)) t as cut_fsign_record 16 ) t2 17 where cut_fsign_record<>‘‘ 18 group by fuser_id 19 ;
1 问题2答案:没看懂,修改 2 3 create table t_user_max_days as 4 select fuser_id 5 ,max(sign_in) 6 from 7 (select fuser_id 8 ,fdate-lag(fate) over (partition by fuser_id order by fate desc ) as sign_in from 9 (select fuser_id,fdate 10 from t_user_attendence 11 where fis_sign_in =0 12 order by fdate desc)a 13 ) t1 14 group by fuser_id 15 ;
2. Python题目
题目:针对股票的最大回撤率指标定义,给出代码实现思路。给定的是产品所有交易日的净值序列,且其净值序列已按照日期排序。
最大回撤率:在选定周期内任一历史时点往后推,产品净值走到最低点时的收益率回撤幅度的最大值。
追问:如何在提升计算效率?
这道题类似的题目其实在leecode也有,这个大概是变化但类似版本(可以搜leecode股票最大回报);因为团队里处理比较多金融资产数据,这个指标是策略中最常见的指标之一,所以也是一道工作中攒下来的题目。这个指标的计算优化问题真的非常值得问,我后面会列几个版本的代码思路和实现代码。
通常最简单的计算实现,会需要O(n2)的计算复杂度;可以针对如何降低计算复杂度,专门追问。
1 最大回撤率:输入参数都是按照日期降序排列的净值序列 2 基础实现版本: 3 4 def max_drawdown(accnavArr): 5 mdd = 0 6 for i in range(0, len(accnavArr)): 7 for j in range(i + 1, len(accnavArr)): 8 drawdown = accnavArr[i] / accnavArr[j] - 1 9 if drawdown < mdd: 10 mdd = drawdown 11 return mdd 12 空间换时间实现版本: 13 14 把每个时间点计算的最大值都存到一个列表结构中,最大回撤的计算只需要再依赖这个列表进行多一次循环计算。 15 16 def maxDrawdownGainCal(accnavArr): # 默认accnavArr按日期降序排列 17 maxDrawdown = 10000 18 maxGain =0 19 arr_len = len(accnavArr) 20 maxList = [0.0] * arr_len 21 minList = [0.0] * arr_len 22 maxList[arr_len-1] = accnavArr[arr_len-1] 23 minList[arr_len-1] = accnavArr[arr_len-1] 24 for i in range(arr_len-2,-1,-1): 25 if accnavArr[i] > maxList[i+1]: 26 maxList[i] = accnavArr[i] 27 else: 28 maxList[i] = maxList[i+1] 29 if accnavArr[i] < minList[i+1]: 30 minList[i] = accnavArr[i] 31 else: 32 minList[i] = minList[i+1] 33 for i in range(0,arr_len): 34 mdd = (accnavArr[i]/maxList[i]-1) 35 mg = (accnavArr[i]/minList[i]-1) 36 if mdd < maxDrawdown : maxDrawdown = mdd 37 if mg > maxGain : maxGain = mg 38 return maxDrawdown,maxGain 39 当前最优版本: 40 41 每个时间点同时更新最大值和最大回撤,两个指标,不需要额外空间,且只做一次列表循环计算。 42 43 def maxDrawdownGainCal(accnavArr): # 默认accnavArr按日期降序排列 44 maxDrawdown = 10000 45 maxGain =0 46 arrLen = len(accnavArr) 47 startMdd = accnavArr[arrLen-1] 48 startGain = accnavArr[arrLen-1] 49 for i in range(arrLen-2,-1,-1): 50 if accnavArr[i] > startMdd: 51 startMdd = accnavArr[i] 52 mdd = (accnavArr[i]/startMdd-1) 53 if accnavArr[i] < startGain: 54 startGain = accnavArr[i] 55 mg = (accnavArr[i]/startGain-1) 56 if mdd < maxDrawdown : maxDrawdown = mdd 57 if mg > maxGain : maxGain = mg 58 return maxDrawdown,maxGain
参考:https://mp.weixin.qq.com/s/HRo1HYog-N6QORsl4WY03Q
标签:输入参数 限制 更新 空间换时间 最大的 今天 fat 指标 nic
原文地址:https://www.cnblogs.com/zhanghongpan/p/12625875.html