Any*_*ny1 5 java performance power-law
嘿,我正在开发一个文本生成器,它应该生成数百万个不同的文本。为了使每个文本的内容更加真实,我使用了齐普夫定律,效果很好,单词分布正确。
但是以下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;
}
Run Code Online (Sandbox Code Playgroud)
编辑:我从以下位置获得了代码: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;
Run Code Online (Sandbox Code Playgroud)
值为rank,0则频率为Infinity,并且会扰乱一些统计数据。
我试图纠正这些错误,但没有分析实现,也没有将其与Zipf 分布函数的定义进行比较。因此,如果有人复制我的代码,他可能会发现它仍然“......有一些问题”。
严格来说,该函数的实现next并不“完全正确”,因为它不一定会终止。没有什么可以阻止循环永远运行。根据参数的不同,终止可能或多或少需要一段时间。我认为这也是“性能”问题的主要原因之一:对于某些值,这种情况(dice < frequency)不太可能发生......
不管怎样,你想要实现的目标可以更通用地表述:你有一定的概率分布。您需要一个“随机”函数,它根据该分布返回随机值。
实现此目的的一种简单而通用的方法是将(累积)概率分布映射到带有 的目标值NavigableMap。然后,给定实例提供的 0.0 到 1.0 之间的随机值,该映射可用于快速查找目标值java.util.Random。
对于特定情况可能有更有效的解决方案,但同样:这是非常通用和简单的(并且仍然相当有效)。
我在这里为 Zipf 发行版实现了这个。再说一次,我没有详细验证所有内容,并且有一些+1/-1奇怪的地方(在第一段中提到),但它应该显示这个想法:填充FastZipfGenerator包含概率分布的地图,并且在函数中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;
    }
}
Run Code Online (Sandbox Code Playgroud)
它打印随机样本结果(基本上是“直方图”)和一些计时结果。计时结果类似于
duration 6221.835052
duration 304.761282
Run Code Online (Sandbox Code Playgroud)
表明它很可能会更快(尽管这不应被视为“基准”......)
|   归档时间:  |  
           
  |  
        
|   查看次数:  |  
           2564 次  |  
        
|   最近记录:  |