将概率矩阵乘以大量迭代中的不正确值 [英] Multiplying the probability matrix, incorrect values on a large number of iterations

查看:74
本文介绍了将概率矩阵乘以大量迭代中的不正确值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有下一个代码,它将概率矩阵 p 乘以一定次数.对于前50次迭代,一切正常,每行的概率之和等于 1 ,但随后我收到 sum>1 ,大约在第70次迭代中,我收到无穷大值.而且我不明白为什么.

I have the next code, which multiplies the probability matrix p the certain number of times. For the first 50 iterations everything is ok, the sum of probabilities in each row is equal to 1, but then I recieve the sum > 1 and approximately on the 70th iteration I recieve infinity values. And I do not understand why.

每行概率的 sum 必须等于 1 .这是经典的 Markov链模型.而且,无论乘法数是多少,您都必须在每行中接收到 sum = 1 .我想浮点计算有问题.

The sum of probabilities in each row must be equal to 1. This is the classic Markov's chain model. And regardless of num of multiplications you must receive the sum = 1 in each row. I suppose there is a problem in a floating-point calculation.

public class Test {
    public static void main(String[] args) {
        int trials = Integer.parseInt(args[0]);

        double[][] p = {
                {0.02, 0.92, 0.02, 0.02, 0.02},
                {0.02, 0.02, 0.38, 0.38, 0.2},
                {0.02, 0.02, 0.02, 0.92, 0.02},
                {0.92, 0.02, 0.02, 0.02, 0.02},
                {0.47, 0.02, 0.47, 0.02, 0.02}};

        for (int t = 0; t < trials; t++) {
            p = multiply(p, p);
        }

        for (int i = 0; i < p.length; i++) {
            for (int j = 0; j < p[i].length; j++) {
                System.out.printf("%9.4f", p[i][j]);
            }
            System.out.println();
        }
    }

    public static double[][] multiply(double[][] a, double[][] b) {
        int w = a[0].length;
        int l = b.length;
        if (w != l) {
            throw new IllegalArgumentException("The number of columns " +
                    "in the first matrix must be equal to the number " +
                    "of rows in second matrix!" + w + " " + l);
        }

        double[][] result = new double[a.length][b[0].length];
        for (int i = 0; i < a.length; i++) {
            for (int j = 0; j < b[0].length; j++) {
                for (int k = 0; k < b.length; k++) {
                    result[i][j] += a[i][k] * b[k][j];
                }
            }
        }
        return result;
    }
}

/*
output for the trials = 30:
   0,2730   0,2657   0,1462   0,2472   0,0678
   0,2730   0,2657   0,1462   0,2472   0,0678
   0,2730   0,2657   0,1462   0,2472   0,0678
   0,2730   0,2657   0,1462   0,2472   0,0678
   0,2730   0,2657   0,1462   0,2472   0,0678

output for the trials = 45:
   0,2732   0,2659   0,1463   0,2474   0,0679
   0,2732   0,2659   0,1463   0,2474   0,0679
   0,2732   0,2659   0,1463   0,2474   0,0679
   0,2732   0,2659   0,1463   0,2474   0,0679
   0,2732   0,2659   0,1463   0,2474   0,0679

output for the trials = 55:
   0,5183   0,5044   0,2775   0,4693   0,1288
   0,5183   0,5044   0,2775   0,4693   0,1288
   0,5183   0,5044   0,2775   0,4693   0,1288
   0,5183   0,5044   0,2775   0,4693   0,1288
   0,5183   0,5044   0,2775   0,4693   0,1288

output for the trials = 70:
 Infinity Infinity Infinity Infinity Infinity
 Infinity Infinity Infinity Infinity Infinity
 Infinity Infinity Infinity Infinity Infinity
 Infinity Infinity Infinity Infinity Infinity
 Infinity Infinity Infinity Infinity Infinity
*/

推荐答案

TL; DR

这只是数学.在第57次迭代中,数字超过1,并将它们相乘,它们很快就会达到 Infinity .

您要乘以和添加 0>num>1 .在您的数据示例中,通过相乘(很明显)将其远离0,并通过相加将其更接近1.
您的乘法大部分是 0.92 * 0.38 0.47 * 0.92 等.通过将它们相加,它们会逐渐接近 1 .
在第57次迭代中,某些总和超过了 1 .之后,乘法进入几何级数,并很快达到 Infinity .为了更好地看到增加,请尝试:

You are multiplying and adding numbers that are 0 > num > 1. With your data example it gets further away from 0 by multiplying (obviously) and getting closer to 1 by adding together.
Your multiplications are mostly 0.92 * 0.38, 0.47 * 0.92 etc. By adding them together they are slowly getting closer to 1.
At 57th iteration some sums are exceeding 1. After that the multiplication goes into a geometric progression and soon reaches Infinity. To better see the increase, try:

public static double[][] multiply(double[][] a, double[][] b) {
    int w = a[0].length;
    int l = b.length;
    if (w != l) {
        throw new IllegalArgumentException("The number of columns " +
                "in the first matrix must be equal to the number " +
                "of rows in second matrix!" + w + " " + l);
    }
    double[][] result = new double[a.length][b[0].length];
    for (int i = 0; i < a.length; i++) {
        int c = 0;
        for (int j = 0; j < b[0].length; j++) {
            System.out.println();
            //For debug
            //System.out.println("["+i+","+j+"]");
            for (int k = 0; k < b.length; k++) {
                //For debug
                //System.out.println("ADD: ["+i+","+k+"] * [" +k+","+j+"]");
                result[i][j] += a[i][k] * b[k][j];
                c++;
            }
            //to see all cells of each iteration
            System.out.println(result[i][j]);
        }
    }
    //To see results of 1st cell of each iteration
    System.out.println("Counts: " + result[0][0]);
    return result;
}

测试

只需将数组值之一从0.02更改为0.5或1,您就会发现它更快地达到了Infinity.没什么奇怪的代码.您的测试案例只是一个有趣的边缘案例,它经常在 1 周围跳舞.

有时,经过40或42次迭代的结果似乎相同.
那是因为列的总和增长得如此缓慢,以致在该点后面的前4个位置看不到它.

Sometimes results with 40 or 42 iterations seemed identical.
That was because the sum of columns was increasing so slowly that it wasn't visible in the first 4 positions behind point.

这篇关于将概率矩阵乘以大量迭代中的不正确值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆