我已经阅读了一些关于生成tagcloud权重的对数分布的正确方法的教程。他们中的大多数将标签分组为步骤。这对我来说似乎有些愚蠢,所以我根据我读过的内容开发了自己的算法,以便沿着阈值和最大值之间的logarthmic曲线动态分配标签的计数。这是python中的本质:

from math import log
count = [1, 3, 5, 4, 7, 5, 10, 6]
def logdist(count, threshold=0, maxsize=1.75, minsize=.75):
    countdist = []
    # mincount is either the threshold or the minimum if it's over the threshold
    mincount = threshold<min(count) and min(count) or threshold
    maxcount = max(count)
    spread = maxcount - mincount
    # the slope of the line (rise over run) between (mincount, minsize) and ( maxcount, maxsize)
    delta = (maxsize - minsize) / float(spread)
    for c in count:
        logcount = log(c - (mincount - 1)) * (spread + 1) / log(spread + 1)
        size = delta * logcount - (delta - minsize)
        countdist.append({'count': c, 'size': round(size, 3)})
    return countdist

基本上,如果没有单个计数的对数计算,它将在点之间生成一条直线(mincount,minsize)和(maxcount,maxsize)。

该算法对两点之间的曲线进行了很好的近似,但存在一个缺点。 mincount是一种特殊情况,它的对数产生零。这意味着mincount的大小将小于minsize。我试过编写数字试图解决这个特例,但似乎无法做到正确。目前我只是将mincount视为特殊情况并添加<!> quot; or 1 <!> quot;到logcount行。

是否有更正确的算法在两点之间绘制曲线?

3月3日更新:如果我没弄错的话,我会记录计数,然后将其插入线性方程式。换句话说,在y = lnx,x = 1时,y = 0。这就是mincount所发生的事情。但是mincount不能为零,标签没有使用过0次。

尝试代码并插入您自己的号码进行测试。将mincount作为特殊情况处理对我来说很好,我觉得它比这个问题的实际解决方案更容易。我只是觉得必须才能解决这个问题,并且有人可能会想出一个解决方案。

4月6日更新:简单的 google 搜索出现了我读过的许多教程,但这个可能是步骤标签云的最完整示例。

4月28日更新:响应antti.huima的解决方案:绘制图形时,算法创建的曲线位于两点之间的线下方。我一直试图改变数字,但似乎仍然无法想出一种方法将曲线翻转到线的另一边。我猜测如果函数被改为某种形式的对数而不是指数,它就会完全符合我的需要。那是对的吗?如果是这样,任何人都可以解释如何实现这一目标吗?

有帮助吗?

解决方案

感谢antti.huima的帮助,我重新考虑了我想要做的事情。

采用他解决问题的方法,我想要一个方程式,其中mincount的对数等于两点之间的线性方程。

weight(MIN) = ln(MIN-(MIN-1)) + min_weight
min_weight = ln(1) + min_weight

虽然这给了我一个很好的起点,但我需要让它通过这个点(MAX,max_weight)。它需要一个常数:

weight(x) = ln(x-(MIN-1))/K + min_weight

解决K得到:

K = ln(MAX-(MIN-1))/(max_weight - min_weight)

所以,把这一切都放回到一些python代码中:

from math import log
count = [1, 3, 5, 4, 7, 5, 10, 6]
def logdist(count, threshold=0, maxsize=1.75, minsize=.75):
    countdist = []
    # mincount is either the threshold or the minimum if it's over the threshold
    mincount = threshold<min(count) and min(count) or threshold
    maxcount = max(count)
    constant = log(maxcount - (mincount - 1)) / (maxsize - minsize)
    for c in count:
        size = log(c - (mincount - 1)) / constant + minsize
        countdist.append({'count': c, 'size': round(size, 3)})
    return countdist

其他提示

让我们从您记录的计数到大小的映射开始。那是你提到的线性映射:

   size
    |
max |_____
    |   /
    |  /|
    | / |
min |/  |
    |   |
   /|   |
0 /_|___|____
    0   a

其中min和max是最小和最大尺寸,a = log(maxcount)-b。该行是y = mx + c,其中x = log(count)-b

从图中我们可以看到梯度m是(maxsize-minsize)/ a。

我们在y = minsize时需要x = 0,所以log(mincount)-b = 0 - <!> gt; B =日志(mincount)

这给我们留下了以下python:

mincount = min(count)
maxcount = max(count)
xoffset = log(mincount)
gradient = (maxsize-minsize)/(log(maxcount)-log(mincount))
for c in count:
    x = log(c)-xoffset
    size = gradient * x + minsize

如果您想确保最小计数始终至少为1,请将第一行替换为:

mincount = min(count+[1])

在执行min之前将1附加到计数列表中。确保maxcount始终至少为1也是如此。因此,上面的最终代码是:

from math import log
count = [1, 3, 5, 4, 7, 5, 10, 6]
def logdist(count, maxsize=1.75, minsize=.75):
    countdist = []
    mincount = min(count+[1])
    maxcount = max(count+[1])
    xoffset = log(mincount)
    gradient = (maxsize-minsize)/(log(maxcount)-log(mincount))
    for c in count:
        x = log(c)-xoffset
        size = gradient * x + minsize
        countdist.append({'count': c, 'size': round(size, 3)})
    return countdist

你所拥有的是你的计数从MIN到MAX的标签;这里可以忽略阈值问题,因为它等于将低于阈值的每个计数设置为阈值,并且仅在之后取最小值和最大值。

您希望将标记计数映射到<!> quot; weights <!> quot;但是以<!>“对数方式<!>”,这基本上意味着(据我理解)以下内容。首先,带有计数MAX的标签获得max_weight权重(在您的示例中为1.75):

weight(MAX) = max_weight

其次,计数MIN的标签获得min_weight权重(在您的示例中为0.75):

weight(MIN) = min_weight

最后,它认为当你的计数减少1时,权重乘以常数K <!> lt; 1,表示曲线的陡度:

weight(x) = weight(x + 1) * K

解决这个问题,我们得到:

weight(x) = weight_max * (K ^ (MAX - x))

注意,当x = MAX时,指数为零,右边的被乘数为1。

现在我们有额外的要求,即重量(MIN)= min_weight,我们可以解决:

weight_min = weight_max * (K ^ (MAX - MIN))

我们得到

K ^ (MAX - MIN) = weight_min / weight_max

并以双方对数

(MAX - MIN) ln K = ln weight_min - ln weight_max

ln K = (ln weight_min - ln weight_max) / (MAX - MIN)

根据需要右侧是负的,因为K <!> lt;然后

K = exp((ln weight_min - ln weight_max) / (MAX - MIN))

所以现在你有了计算K的公式。在此之后你只需申请MIN和MAX之间的任何计数x:

weight(x) = max_weight * (K ^ (MAX - x))

你已经完成了。

在对数刻度上,您只是线性绘制数字的对数(换句话说,假装您是线性绘制,但是先记录要绘制的数字的对数)。

零问题无法通过分析解决 - 您必须为您的比例选择最小数量级,无论您不能达到零。如果你想将某些东西绘制为零,你可以选择任意给它一个最小的量级,或者省略它。

我没有确切的答案,但我认为你想查找线性化指数数据。首先计算通过这些点的直线方程,然后取该方程两边的对数。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top