嘿,我正在研究一个文本生成器,它应该生成数百万种不同的文本.
为了使每个文本的内容变得现实,我使用了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;
}
解决方法:
您复制的实现…有一些问题.人们可能会说这显然是错误的,因为它使用的是随机值,而且在计算时就像
rank = rnd.nextInt(size);
friquency = (1.0d / Math.pow(rank, this.skew)) / this.bottom;
等级值为0,则频率为无穷大,并且会混淆一些统计数据.
我试图纠正这些错误,但没有分析实现,也没有将它与Zipf分配函数的定义进行比较.因此,如果有人复制我的代码,他可能会发现它仍然“……有一些问题”.
严格地说,下一个功能的实现不是“total correct”,因为它不一定终止.没有什么能阻止循环永远运行.根据参数的不同,它可能或多或少地需要一段时间才能终止.而且我认为这也是导致“性能”问题的主要原因之一:对于某些值,条件(骰子和频率)不太可能发生……
无论如何,您想要实现的目标可以更一般地制定:您有一定的概率分布.并且您想要一个“随机”函数,它根据此分布返回随机值.
实现此目的的一种简单而通用的方法是使用NavigableMap将(累积的)概率分布映射到目标值.然后,可以使用此映射快速查找目标值,给定java.util.Random实例提供的介于0.0和1.0之间的随机值.
对于特定情况,可能会有更有效的解决方案,但同样:这是非常通用和简单的(并且仍然合理有效).
我在这里实现了Zipf发行版.同样,我没有详细验证所有内容,并且有一些1 / -1个奇怪(在第一段中提到),但它应该显示出来:FastZipfGenerator填充包含概率分布的地图,并在下一个()函数,只执行查找:
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 counts0 = computeCounts(z0, size, n);
after = System.nanoTime();
System.out.println(counts0+", duration "+(after-before)/1e6);
before = System.nanoTime();
Map counts1 = computeCounts(z1, size, n);
after = System.nanoTime();
System.out.println(counts1+", duration "+(after-before)/1e6);
}
private static Map computeCounts(
ZipfGenerator z, int size, int n)
{
Map counts = new LinkedHashMap();
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 computeCounts(
FastZipfGenerator z, int size, int n)
{
Map counts = new LinkedHashMap();
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 map;
FastZipfGenerator(int size, double skew)
{
map = computeMap(size, skew);
}
private static NavigableMap computeMap(
int size, double skew)
{
NavigableMap map =
new TreeMap();
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,performance,power-law
来源: https://codeday.me/bug/20190824/1712735.html