5

我已经阅读了一堆关于生成标记云权重对数分布的正确方法的教程。他们中的大多数将标签分组为步骤。这对我来说似乎有点傻,所以我根据我读过的内容开发了自己的算法,以便它沿着阈值和最大值之间的对数曲线动态分布标签的计数。这是它在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 视为一种特殊情况,并将“ or 1”添加到 logcount 行。

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

3 月 3 日更新:如果我没记错的话,我正在记录计数,然后将其代入线性方程。换句话说,就是对特殊情况的描述,在 y=lnx at x=1, y=0。这就是 mincount 发生的情况。但是mincount不能为零,标签没有被使用过0次。

尝试代码并插入您自己的数字进行测试。将 mincount 视为特殊情况对我来说很好,我觉得这比实际解决这个问题的方法要容易。我只是觉得必须有一个解决方案,并且有人可能已经提出了解决方案。

更新 4 月 6 日:一个简单的谷歌搜索出现了我读过的许多教程,但这可能是阶梯标签云最完整的例子。

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

4

5 回答 5

2

感谢 antti.huima 的帮助,我重新思考了我想要做什么。

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

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

虽然这给了我一个很好的起点,但我需要让它通过点(MA​​X,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
于 2009-04-30T03:10:14.593 回答
1

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

   尺寸
    |
最大 |_____
    | /
    | /|
    | / |
分钟 |/ |
    | |
   /| |
0 /_|___|____
    0个

其中 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 -> b=log(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
于 2009-03-24T16:01:35.000 回答
1

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

您想将标签计数映射到“权重”,但以“对数方式”,这基本上意味着(据我了解)以下内容。首先,带有 count MAX 的标签获得 max_weight 权重(在您的示例中为 1.75):

weight(MAX) = max_weight

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

weight(MIN) = min_weight

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

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

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

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

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

现在我们有了 weight(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

IE

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

右手边如所愿为负,因为 K < 1。然后

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

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

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

你完成了。

于 2009-03-27T20:19:27.993 回答
0

在对数刻度上,您只需线性绘制数字的对数(换句话说,假装您正在线性绘制,但首先获取要绘制的数字的对数)。

零问题无法通过分析解决——您必须为您的规模选择一个最小数量级,而且无论如何您都无法达到零。如果你想在零处绘制一些东西,你的选择是任意给它比例的最小数量级,或者省略它。

于 2009-03-03T03:15:06.423 回答
0

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

于 2009-03-03T03:58:46.427 回答