gpt4 book ai didi

java - 用于文本生成的 Java Zipf 定律 - 太慢了

转载 作者:塔克拉玛干 更新时间:2023-11-01 22:45:00 27 4
gpt4 key购买 nike

嘿,我正在开发一个文本生成器,它应该可以生成数百万种不同的文本。为了使每篇文章的内容更真实,我使用了 Zipf 定律它运行良好,单词分布正确。

但是下面的 next() 函数执行得非常慢,因为我想生成数百万篇文章,所以必须对其进行更改。 (while循环是慢的部分)

有人可以帮我解决这个问题吗?

我是这样实现的:

   public int next() {

int rank;
double frequency = 0;
double dice;

rank = rnd.nextInt(size);
frequency = (1.0d / Math.pow(rank, this.skew)) / this.bottom;
dice = rnd.nextDouble();


while (!(dice < frequency) || (rank == 0)) {
rank = rnd.nextInt(size);
frequency = (1.0d / Math.pow(rank, this.skew)) / this.bottom;
dice = rnd.nextDouble();
}

return rank;
}

编辑:我从以下位置获得代码:http://diveintodata.org/2009/09/13/zipf-distribution-generator-in-java/

最佳答案

您复制的实现...有一些问题。人们可能会说这显然是错误的,因为它使用的是随机值,并且在像

这样的计算中
rank = rnd.nextInt(size);
friquency = (1.0d / Math.pow(rank, this.skew)) / this.bottom;

rank值为 0 , 则频率为 Infinity ,并弄乱了一些统计数据。

我试图更正这些错误,但没有分析实现,也没有将其与 Zipf 分布函数的定义进行比较.因此,如果有人复制我的代码,他可能会发现它仍然“......有一些问题”


执行next严格来说,函数不是“total correct”,因为它不一定终止。没有什么能阻止循环永远运行。根据参数的不同,它可能或多或少需要一段时间才能终止。而且我认为这也是您的“性能”问题的主要原因之一:对于某些值,条件 (dice < frequency)只是不太可能发生....


无论如何,您想要实现的目标可以更一般地表述:您有一定的概率分布。你想要一个“随机”函数,它根据这个分布返回随机值。

实现此目的的一种简单而通用的方法是使用 NavigableMap 将(累积的)概率分布映射到目标值。 .然后可以使用此映射快速查找目标值,给定一个介于 0.0 和 1.0 之间的随机值,该值由 java.util.Random 提供。实例。

对于特定情况可能有更有效的解决方案,但同样:这是非常通用和简单的(而且仍然相当有效)。


我在这里为 Zipf 发行版实现了这个。同样,我没有详细验证所有内容,并且有一些 +1/-1奇怪之处(在第一段中提到),但它应该表明这个想法:FastZipfGenerator填充包含概率分布的 map ,并在 next() 中功能,只是执行查找:

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Random;
import java.util.TreeMap;

public class ZipfGeneratorTest
{
public static void main(String[] args) {

int size = 10;
double skew = 2.0;

ZipfGenerator z0 = new ZipfGenerator(size, skew);
FastZipfGenerator z1 = new FastZipfGenerator(size, skew);

long before = 0;
long after = 0;

int n = 5000000;

before = System.nanoTime();
Map<Integer, Integer> counts0 = computeCounts(z0, size, n);
after = System.nanoTime();
System.out.println(counts0+", duration "+(after-before)/1e6);

before = System.nanoTime();
Map<Integer, Integer> counts1 = computeCounts(z1, size, n);
after = System.nanoTime();
System.out.println(counts1+", duration "+(after-before)/1e6);
}

private static Map<Integer, Integer> computeCounts(
ZipfGenerator z, int size, int n)
{
Map<Integer, Integer> counts = new LinkedHashMap<Integer, Integer>();
for (int i=1; i<=size; i++)
{
counts.put(i, 0);
}
for (int i=1; i<=n; i++)
{
int k = z.next();
counts.put(k, counts.get(k)+1);
}
return counts;
}

private static Map<Integer, Integer> computeCounts(
FastZipfGenerator z, int size, int n)
{
Map<Integer, Integer> counts = new LinkedHashMap<Integer, Integer>();
for (int i=1; i<=size; i++)
{
counts.put(i, 0);
}
for (int i=1; i<=n; i++)
{
int k = z.next();
counts.put(k, counts.get(k)+1);
}
return counts;
}

}

// Based on http://diveintodata.org/tag/zipf/
class ZipfGenerator {
private Random rnd = new Random(0);
private int size;
private double skew;
private double bottom = 0;

public ZipfGenerator(int size, double skew) {
this.size = size;
this.skew = skew;

for(int i=1;i <=size; i++) {
this.bottom += (1/Math.pow(i, this.skew));
}
}

// the next() method returns an random rank id.
// The frequency of returned rank ids are follows Zipf distribution.
public int next() {
int rank;
double friquency = 0;
double dice;

rank = rnd.nextInt(size)+1;
friquency = (1.0d / Math.pow(rank, this.skew)) / this.bottom;
dice = rnd.nextDouble();

while(!(dice < friquency)) {
rank = rnd.nextInt(size)+1;
friquency = (1.0d / Math.pow(rank, this.skew)) / this.bottom;
dice = rnd.nextDouble();
}

return rank;
}


// This method returns a probability that the given rank occurs.
public double getProbability(int rank) {
return (1.0d / Math.pow(rank, this.skew)) / this.bottom;
}
}



class FastZipfGenerator
{
private Random random = new Random(0);
private NavigableMap<Double, Integer> map;

FastZipfGenerator(int size, double skew)
{
map = computeMap(size, skew);
}

private static NavigableMap<Double, Integer> computeMap(
int size, double skew)
{
NavigableMap<Double, Integer> map =
new TreeMap<Double, Integer>();

double div = 0;
for (int i = 1; i <= size; i++)
{
div += (1 / Math.pow(i, skew));
}

double sum = 0;
for(int i=1; i<=size; i++)
{
double p = (1.0d / Math.pow(i, skew)) / div;
sum += p;
map.put(sum, i-1);
}
return map;
}

public int next()
{
double value = random.nextDouble();
return map.ceilingEntry(value).getValue()+1;
}

}

它打印随机样本结果(基本上是“直方图”)和一些计时结果。计时结果是这样的

duration 6221.835052
duration 304.761282

显示它很可能会更快(即使这不应被视为“基准”...)

关于java - 用于文本生成的 Java Zipf 定律 - 太慢了,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27105677/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com