21 June 2014

一、需求场景

先上一张效果图:

mapLabel

点我查看线上效果

产品需求是这样子的:把各部剧目的播放指数最高的八个省份,在左侧的地图中用实心圆进行标注,指数越高,圆的半径越大。在右侧用条形图把这top 8的省份展示出来,指数越高,条的长度越长。

限于页面展示空间,地图标注时,圆的半径取值范围为[4,10],条的width取值范围在[10%,100%](条形图由css实现,js通过设置width的百分比来适应数据),即指数最高的省份在标记时用半径为10的圆和width为100%的条,第八高的省份用半径为4的圆和width为10%的条。

问题现在归结为:把最高的八个省份的指数,转换输出为[4,10]和[10%, 100%]区间之内的数,同时要保证单调递增,越大的指数,转换后的半径和width越大

现在来看看输入,最高的八个省份的指数数据分布是什么样子呢? 以生活启示录当前的top 8指数数据为例:

[{"name":"上海","value":4186447},{"name":"江苏","value":2505809},{"name":"黑龙江","value":2410871}, {"name":"北京","value":2090109},{"name":"湖南","value":1889304},{"name":"安徽","value":1818746}, {"name":"陕西","value":1749618},{"name":"天津","value":1698673}]

区间为[1698673, 4186447],与输出区间[4,10][0.1,1]无比例关系。线上的输入区间范围可能更大,因为取的是用户选择的三部剧进行对比,最大值是最热门的剧的指数最高的省份的指数,最小值是最冷门的剧的第八高省份的指数,这种情况下输入的最大值和最小值可能差别好几个数量级。

现在问题就成了:给定任意大小的区间[minInput, maxInput], 提供单调递增转换方法,将输入区间内的数输出为[minOutput, maxOutput]的数。

二、解决方案

不啰嗦废话了,直接写一下解决方法:线性函数转换

就是用函数y = a * x + b对输入数据进行处理,问题就是求参数a和b。求法为解下面的方程:

minOutput = a * minInput + b

maxOutput = a * maxInput + b

求解出来的结果是:

a = (maxOutput - minOutput) / (maxInput - minInput)

b = minOutput - a * minInput

线性转换是最简单的方式了,这类问题,称为数据归一化,or 数据处理之标准化/归一化。

三、花絮

我是怎么知道这个问题的解决方法的呢?

嘿嘿,是我求助我们公司用户行为分析团队的同事,他们告诉我的!他们负责提供这次视频指数页面的数据。

其实他们还告诉我一个听起来更高大上的方法:sigmoid函数f(x) = 1/[1+e^(-x)]。我粗略看一下,这个函数在x趋于正无穷时值为1,在x趋于负无穷时值为0,还要再调整下sigmoid函数才能满足我的需求:x趋于maxInput时,值为10,x趋于minInput时值为4。我觉得这个函数看上去太复杂,就没采用sigmoid函数(其实是我不会啊!)。



blog comments powered by Disqus