非线性Granger因果关系发现的可解释稀疏神经网络模型

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了非线性Granger因果关系发现的可解释稀疏神经网络模型相关的知识,希望对你有一定的参考价值。

参考技术A 虽然大多数经典的格兰杰因果关系检测方法依赖于线性时间序列假设,但神经科学和经济学应用中的许多交互作用是非线性的。我们发展了一种使用多层感知器的非线性格兰杰因果关系检测方法,其中网络的输入是所有序列的过去时间滞后,输出是单个序列的未来值。在这种情况下,Granger非因果关系的一个充分条件是,输入数据的所有输出权重(序列的过去滞后)到第一个隐藏层都为零。对于估计,我们使用一组套索惩罚将输入权重组缩小为零。我们还提出了一个等级惩罚同时格兰杰因果关系和滞后估计。我们在稀疏线性自回归模型和稀疏非线性Lorenz-96模型的模拟数据上验证了我们的方法。

格兰杰因果关系量化了一个时间序列的过去活动对另一个时间序列的预测程度。当研究一个完整的时间序列系统时,相互作用网络可能会被发现[2]。经典上,估计格兰杰因果关系的大多数方法假设线性时间序列动力学,并使用流行的向量自回归(VAR)模型[9,8]。然而,在许多现实世界的时间序列中,序列之间的依赖是非线性的,使用线性模型可能导致格兰杰因果相互作用的不一致估计[12,13]。估计时间序列中相互作用的常见非线性方法使用加法模型[12,4,11],其中每个序列的过去可能有一个相加的非线性效应,在序列之间解耦。然而,加性模型可能会忽略预测因子之间重要的非线性相互作用,因此也可能无法检测到重要的Granger因果关系。

为了解决这些挑战,我们提出了一个框架,以解释非线性格兰杰因果关系发现使用正则化神经网络。用于时间序列分析的神经网络模型传统上只用于预测和预测,而不用于解释。这是因为,由于隐藏层中相互作用的节点错综复杂,输入的影响难以精确量化。我们避开了这个困难,而是构建了一个简单的体系结构,允许我们精确地选择对输出没有线性或非线性影响的时间序列。

我们将最近关于神经网络体系结构选择稀疏诱导惩罚的研究[1,7]应用到我们的案例中。特别是,我们通过在输入的输出权重上添加一组套索惩罚[14]来选择格兰杰因果关系,我们称之为编码选择。我们还探讨了一种自动滞后选择的分层套索惩罚[10]。当真实的非线性相互作用网络是稀疏的时,该方法将选取Granger引起的输出序列和这些相互作用的滞后的几个时间序列

java算法--稀疏数组

数据结构必要知识

线性结构

  • 线性结构是最常用的数据结构,数据元素之间存在一对一的线性关系。

  • 线性结构有两种不同的存储结构,即顺序存储结构链式存储结构。顺序存储的线性表称为顺序表,顺序表中的存储元素是连续的。

  • 链式存储的线性表称为链表,链表中的存储元素不一定是连续的,元素节点中存放数据元素以及相邻的地址信息。

  • 线性表结构常见的有:数组,队列,链表,栈

非线性结构

非线性结构包括:二维数组,多维数组,广义表,树结构,图结构(这就不是一对一了)

稀疏数组

基本介绍

  • 定义:

    当一个数组中大部分的元素为0,或为同一个值的数组时,可以使用稀疏数组来保存该数组。

    eg:

      可以用这种数组模拟各种棋盘,迷宫什么的.

    在这里我们用问题驱动的模式:

    我们现在要制作一个棋盘游戏.

    先不考虑这个棋怎么玩.

    我们现在必须要构建出一个二维数组.

    如下面所示.

    *技术图片

    类似这个就是一个棋盘

    • 用0表示没有被下过的地方.
    • 用1表示黑子.
    • 用2表示蓝子.

    无疑这么大的一个棋盘所需要记录的东西有点太多了,太耗费空间了,有没有简单一点的办法?

    办法就是:

    稀疏矩阵

    回到刚才的图片中.

    我们发现其中大部分的数字都是重复的,基本都是0,实际上我们真正在乎的就只有有棋子的部分就是上面那个二维数组中有1,2的节点.

    稀疏编号 row col val
    0 11 11 2
    1 1 2 1
    2 2 3 2

    这就是图片中棋盘的稀疏矩阵(就是第二张图片的简化版本).

    一个二阶数组.

    用这么一个简单的方式就可以轻松的描绘出那个复杂的充满了0和1的正方形棋盘.

    那我们都要记录什么内容呢

    • 棋盘大小

    • 上面棋子的落点

于是我们就知道了真正的问题就是如何存储这些数据.

  1. 稀疏编号为0的那一行里面保存的是关于这个棋盘的数据.

    • 11行

    • 11列

    • 里面有2个棋子.

  2. 稀疏编号从1开始的那些行保存的是关于棋子的信息

    • col 第几列
    • row 第几行
    • val 是哪种棋子
  • 稀疏数组处理的方法是:

    • 记录数组一共有几行几列,有多少个不同的值

    • 把具有不同值的元素的行列值记录在一个小规模的数组(稀疏数组)中,从而缩小程序的规模。

既然我们知道了这些,那么基本就可以清楚稀疏数组的运行方式:
用第一行的那个数组创建整个棋盘,用剩下的数组建立各种棋子.

那么就开始看代码吧:
首先必须知道一点,稀疏数组出现之前必须现有一个对应的二维数组(就是那个满是0与1的棋盘).
要不然这....这思维真有点厉害了.
所以我们可以先看一段制造二维数组(棋盘)的代码

 //创建一个原始的二维数11*11
        //0表示没有旗子,1表示黑子,2表示蓝子
        //这里在程序中手动输入棋子...low一点.
        int chessArr1[][] = new int[11][11];
        chessArr1[1][2] = 1;
        chessArr1[2][3] = 2;
        //输出原始的二维数组
        for (int[] row : chessArr1) {
            for (int data : row) {
                System.out.println("原始的二维数组");
                System.out.printf("%d	", data);
            }
            System.out.println();//换行用
        }

好了,棋盘制造完毕,这个棋盘就是图中的棋盘.

然后我们想办法将这个二位数组(棋盘)化为稀疏数组

  1. 我们先完成对于稀疏数组第一行的构建(别忘了,这一行可和其它行不一样哦)
    • 这一行中有三个值,一个是二位数组行数,一个是二维数组列数,一个是棋盘中棋子数所以我们要遍历整个数组.
     //1.先遍历二维数组 得到非0数据的个数
         int sum = 0;
         for (int i = 0; i < 11; i++) {
             for (int j = 0; j < 11; j++) {
                 if (chessArr1[i][j] != 0) {
                     sum++;
                 }
             }
         }
    
         //将得到的值放入稀疏数组
          int spareseArr[][] = new int[sum + 1][3];//sum是一共有多少个棋
         //给稀数组赋值
         //这是稀疏数组的第一行,也就是存放标准二维数组(棋盘)信息的地方
         spareseArr[0][0] = 11;//有多少行
         spareseArr[0][1] = 11;//有多少列
         spareseArr[0][2] = sum;//必须拿到sum才能创建数组(sum在棋盘上有几个棋子)

现在遍历完了数组,我们知道了第一行,现在我们要继续完成之后的行数了.

  1. 现在开始第二行的构建,第二行开始存储的是每个棋子的行,列,值(颜色).想要得到这些消息
    就必须再次遍历整个数组,找到这些棋盘.
     /*稀疏数组已经创建过了.spareseArr[][]
       int chessArr1[][] = new int[11][11];//二维数组(棋盘)
       */
     //遍历二维数组,将非0的值放到sparseArr中
        int count = 0;//count 用于记录是第几个非0数据
        for (int i = 0; i < 11; i++) {
            for (int j = 0; j < 11; j++) {
                if (chessArr1[i][j] != 0) {
                //count是从1开始的,并不存在第0个棋子,但是却存在数组中的第0个元素,正好和第一行错开.
                    count++;//代表的是第几个棋子。  spareseArr[count]中存放的一维数组中存放的内容就是这个棋子的信息。
                    spareseArr[count][0] = i;//第一列,存放(非零数据)棋子在普通数组(棋盘)中的位置(行数)
                    spareseArr[count][1] = j;//第二列,存放(非零数据)棋子在普通数组(棋盘)中的位置(列数)
                    spareseArr[count][2] = chessArr1[i][j];//第三列,存放(非零数据)数据。(是黑棋蓝棋)
                }
            }
        }

就这样我们构建了第0行和剩下的稀疏矩阵.

但是我们不仅如此,虽然将那么大的一个棋盘压缩了.

但是我们还要把这个棋盘复原.

那就要将稀疏数组化为二维数组(棋盘)

//将稀疏数组--》恢复成二维数组
        /**
         * 1.先读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组,比如上面的chressArray
         * 2.在读取稀疏数组后几行的数据,并赋给原始的二维数组即可。
         */
        //1.先读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组
        //稀疏数组第一列是普通二维数组的行,第二列是普通数组的列
        int chessArr2[][] = new int[spareseArr[0][0]][spareseArr[0][1]];//普通数组
        //2.在读取稀疏数组后几行的数据(从第二行开始),并付给原始的二维数组即可

        //之所以从1开始,是因为稀疏矩阵第一行存的是普通数组的信息
        for (int i=1;i<spareseArr.length;i++){
            chessArr2[spareseArr[i][0]][spareseArr[i][1]]=spareseArr[i][2];
            //chessArr2[spareseArr[i][0]非零数据所在行][spareseArr[i][1]非零数据所在列]=spareseArr[i][2]非零数据的值。
        }
        //输出恢复后的二维数组
        System.out.println("恢复后的二维数组");
        for (int[] row : chessArr2) {
            for (int data : row) {

                //关于printf相关知识:https://blog.csdn.net/qq_39017218/article/details/80042287
                System.out.printf("%d	", data);

            }
            System.out.println();
        }
    }
}

这里解释的很清楚了,就不多叙述了,这就是java算法中最简单的一种,稀疏数组.

以上是关于非线性Granger因果关系发现的可解释稀疏神经网络模型的主要内容,如果未能解决你的问题,请参考以下文章

Granger Causality 格兰杰因果关系

R语言中Granger因果检验的函数在哪个程序包中

神经网络的可解释性

神经网络的可解释性

神经网络的可解释性

论文分享ACL 2020 神经网络的可解释性