2点間の対数分布曲線の正しいアルゴリズムは何ですか?
質問
タグクラウドの重みの対数分布を生成する適切な方法についてのチュートリアルをたくさん読みました。それらのほとんどは、タグをステップにグループ化します。これはやや馬鹿げているように思えるので、読んだ内容に基づいて独自のアルゴリズムを開発し、しきい値と最大値の間の対数曲線に沿ってタグのカウントを動的に分散させました。これが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)の間に直線を生成します。
アルゴリズムは、2点間の曲線を適切に近似しますが、1つの欠点があります。 mincountは特殊なケースであり、その対数はゼロを生成します。これは、mincountのサイズがminsizeより小さいことを意味します。この特殊なケースを解決するために数字を整理してみましたが、うまくいかないようです。現在、私はmincountを特別なケースとして扱い、<!> quot; or 1
<!> quot;を追加しています。 logcount行に。
2点間に曲線を描くためのより正確なアルゴリズムはありますか?
3月3日更新:間違っていない場合は、カウントのログを取得し、それを線形方程式にプラグインします。言い換えると、特別な場合の説明を、x = 1、y = 0のy = lnxに記述します。これがmincountで発生することです。ただし、mincountをゼロにすることはできません。タグは0回使用されていません。
コードを試して、テストするために独自の番号を差し込みます。特別なケースとしてmincountを扱うことは私にとっては問題ありませんが、この問題の実際の解決策が何であれよりも簡単だと感じています。これに対する解決策が ある必要があり、誰かがおそらく解決策を考え出しているように感じます。
4月6日更新:簡単な google 検索により、私が読んだ多くのチュートリアルが表示されますが、これはおそらくステップ付きタグクラウドの最も完全な例。
UPDATE 4月28日:antti.huimaのソリューションに応じて:グラフ化すると、アルゴリズムが作成する曲線は2点間の線の下にあります。私は周りの数字をジャグリングしようとしましたが、それでもその曲線を線の反対側に反転させる方法を思い付くことができないようです。関数が指数ではなく対数形式に変更された場合、必要なことを正確に行えると推測しています。あれは正しいですか?もしそうなら、誰でもこれを達成する方法を説明できますか?
解決
antti.huimaの支援のおかげで、私がやろうとしていたことを再考しました。
問題を解決する彼の方法を取り上げて、最小カウントの対数が2点間の線形方程式に等しい方程式が必要です。
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
ここで、最小値と最大値は最小値と最大値サイズであり、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 = 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
あなたが持っているのは、MINからMAXまでのカウントを持つタグがあるということです。ここでは、しきい値を下回るすべてのカウントをしきい値に設定し、その後でのみ最小値と最大値を取得するため、しきい値の問題は無視できます。
タグカウントを<!> quot; weights <!> quot;にマップします。しかし、<!> quot;対数形式<!> quot;であり、これは基本的に(私が理解しているように)以下を意味します。まず、count 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になることに注意してください。
これで、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
i.e。
ln K = (ln weight_min - ln weight_max) / (MAX - MIN)
K <!> lt; 1.その後
K = exp((ln weight_min - ln weight_max) / (MAX - MIN))
これで、Kを計算する公式ができました。この後、MINとMAXの間の任意のカウントxを適用します。
weight(x) = max_weight * (K ^ (MAX - x))
これで完了です。
対数目盛では、数値の対数を線形にプロットします(つまり、線形にプロットしているように見せますが、最初にプロットする数値の対数を取得します)。
ゼロの問題は分析的に解決することはできません。ゼロに到達できない場合でも、スケールの最小桁を選択する必要があります。ゼロで何かをプロットしたい場合は、スケールの最小次数を任意に指定するか、省略します。
正確な答えはありませんが、線形化指数データを調べたいと思います。まず、点を通る直線の方程式を計算し、その方程式の両側の対数を取得します。