网络拓扑结构5-9-1读取数据库并训练预测

本文针对“网络拓扑结构5-3-1读取数据库并训练预测 ”做了如下改进:

1、网络的拓扑结构由5-3-1改为5-9-1,更加接近理论值“隐层节点个数=输入层节点个数*2-1”

2、先从数据库读取原始数据,之后进行归一化处理,而不是之前的顺便归一化。这样便于查看从数据库读取的数据是否准确可靠

3、添加了数据补偿的功能,若数据上报有丢失,用前6组(1小时)数据的平均值代替之

4、在训练的时候使用变量控制权值、阈值、误差、隐层数据的下标,而不是之前的硬性绑定。

:::数据背景和上次相同:::

package pa;    
import java.sql.*;  
  
public class BP{  
  
    public static int M=6;  //记录条数   
    public static int N=6;  //字段个数   
    public static double Data[][]=new double[M][N]; //从数据库中读取的原始数据,并归一化   
    public static double Max[]=new double[N];   //各个字段的最大值,归一化和反归一化时要用到   
    public static double Min[]=new double[N];   //各个字段的最小值,归一化和反归一化时要用到   
      
    public static double Step=0.6;  //学习次数   
    public static int TrainTimes=800;  
    public static int L0=5; //输入层节点数   
    public static int L1=9; //隐层节点数   
    public static int L2=1; //输出层节点数   
      
    public static double Weight01[][]=new double[L0][L1];  
    public static double Weight12[][]=new double[L1][L2];  
    public static double Threshold1[]=new double[L1];  
    public static double Threshold2[]=new double[L2];  
      
    /*函数说明 
     * public static void getData()//准备数据 
     * public static void reflect()//将数据归一化处理
     * public static void checkData()//检验数据是否有丢失。若有,用前六组的数据补充
     * public static void init()//初始化权值和阈值 
     * public static double transfer(double x)//传递函数 
     * public static double train(double i1 ,double i2,double i3, double i4,double i5,double d) 
     *      训练函数。输入参数是归一化处理之后的数据,返回正向传播的结果 
     * public static double run(double i1,double i2,double i3,double i4,double i5) 
     *      测试函数。输入参数是归一化处理之后的数据,返回值也是归一化的。和实际值进行比较,需要反归一化 
     *  public static void print()//打印所有的权值和阈值 
     * public static void main(String[] args) //主函数,负责调用训练函数和测试函数,输出测试的结果 
     */  
    public static void getData()  
    {  
        //从数据库中读取   
        String driverName="com.mysql.jdbc.Driver";//驱动程序名   
        String userName="root";//数据库用户名   
        String userPasswd="xhp";//密码   
        String dbName="test";//数据库名   
        String tableName="table713";//表名   
        try  
        {  
            String url="jdbc:mysql://localhost/"+dbName+"?user="+userName+"&password="+userPasswd;//连接字符串  
            Class.forName(driverName);  
            Connection connection=DriverManager.getConnection(url);  
            Statement statement = connection.createStatement();       
            String sql="SELECT * FROM "+tableName+" where ID >=1";  
            ResultSet rs = statement.executeQuery(sql);  
            for(int i=0;i<M;i++)  
            {  
                if(rs.next())  
                {  
                    Data[i][0]=Double.parseDouble(rs.getString("sun"));  
                    Data[i][1]=Double.parseDouble(rs.getString("temprature"));  
                    Data[i][2]=Double.parseDouble(rs.getString("airpress"));  
                    Data[i][3]=Double.parseDouble(rs.getString("PH"));  
                    Data[i][4]=Double.parseDouble(rs.getString("humidity"));  
                    Data[i][5]=Double.parseDouble(rs.getString("DO"));  
                }  
            }  
            rs.close();  
            statement.close();  
            connection.close();  
        }  
        catch(ClassNotFoundException e)  
        {  
            e.printStackTrace();  
        }  
        catch(SQLException e)  
        {  
            e.printStackTrace();  
        }          
    }  
    public static void reflect()
    {
    	//寻找每个字段的最大值最小值   
        for(int i=0;i<N;i++)  
        {  
            Max[i]=-32767;  
            Min[i]=32767;  
            for(int j=0;j<M;j++)  
            {  
                if(Data[j][i]>Max[i])  
                {  
                    Max[i]=Data[j][i];  
                }  
                if(Data[j][i]<Min[i])  
                {  
                    Min[i]=Data[j][i];  
                }  
            }  
        }  
        //归一化处理   
        for(int i=0;i<M;i++)  
        {  
            for(int j=0;j<N;j++)  
            {  
                Data[i][j]=(Data[i][j]-Min[j])/(Max[j]-Min[j]);  
            }  
        }  
    }
    public static void checkData()
	{
		//若前6组数据有缺失的,就没有办法了(需要从数据库中重新读取,很费时间的)
		for(int i=6;i<M;i++)
		{
			for(int j=0;j<N;j++)
			{
				if(Data[i][j]==0)
					{
						double temp=0;
						for(int k=1;k<=6;k++)
						{
							temp+=Data[i-k][j];//从历史记录里面读取6组数据
						}
						Data[i][j]=(float)temp/6;//取平均值					
					}
			}
		}
	}
    public static void printData()  
    {  
        for(int i=0;i<M;i++)  
        {  
            for(int j=0;j<N;j++)  
            {  
                System.out.print(Data[i][j]+"   ");  
            }  
            System.out.println();  
        }  
    }  
    public static void init()  
    {  
        for(int i=0;i<L0;i++)  
        {  
            for(int j=0;j<L1;j++)  
            {  
                Weight01[i][j]=Math.random()*2-1;  
            }  
        }  
        for(int i=0;i<L1;i++)  
        {  
            for(int j=0;j<L2;j++)  
            {  
                Weight12[i][j]=Math.random()*2-1;  
            }  
        }  
        for(int i=0;i<L1;i++)  
        {  
            Threshold1[i]=Math.random()*2-1;  
        }  
        for(int i=0;i<L2;i++)  
        {  
            Threshold2[i]=Math.random()*2-1;  
        }  
    }  
    public static double transfer(double x)  
    {  
        return 1/(1+Math.exp(-x));  
    }  
    public static double train(double i1 ,double i2,double i3, double i4,double i5,double d)  
    {  
    	double Input[]=new double[L0];//输入层单元
    	double Hide[]=new double[L1];//隐层单元    	
        double out=0;//输出层的输出  
        //设置输入层的数值
        Input[0]=i1;
        Input[1]=i2;
        Input[2]=i3;
        Input[3]=i4;
        Input[4]=i5;
        
        //计算隐含层的神经元值,隐层的输入   
        for(int i=0;i<L1;i++)
        { 
        	for(int j=0;j<L0;j++)
        	{
        		Hide[i]+=Input[j]*Weight01[j][i];
        	}
        	Hide[i]+=Threshold1[i];
        }        
  
        //使用S函数,隐层的输出   
        for(int i=0;i<L1;i++)
        {
        	Hide[i]=transfer(Hide[i]);
        }
        
        //计算输出层的值,输出层的输入   
        for(int i=0;i<L2;i++)
        {
        	for(int j=0;j<L1;j++)
        	{
            	out+=Hide[j]*Weight12[j][i];        		
        	}
        	out+=Threshold2[i];
        }          
        
        //使用S函数,输出层的输出   
        out=transfer(out);  
  
        //计算误差,反向传播   
        double error1[]=new double[L1];//隐层的误差  
        double error2[]=new double[L2];//输出层的误差  
        	
        	//计算输出层的误差
        error2[0]=out*(1-out)*(d-out);  
  
        	//计算隐层的误差
        for(int i=0;i<L1;i++)
        {
        	error1[i]=Hide[i]*(1-Hide[i])*(Weight12[i][0])*(error2[0]);  
        }
        
        //调整阈值   ,正向调整
        	//调整隐层的阈值
        for(int i=0;i<L1;i++)
        {  
            Threshold1[i]+=Step*error1[i];  
        }  
        	//输出层的阈值
        Threshold2[0]+=Step*error2[0];  
  
        //调整权值   
        	//输入层和隐层之间的权值
        for(int i=0;i<L0;i++)
        {  
        	for(int j=0;j<L1;j++)
        	{
                Weight01[i][j]+=Step*Input[i]*error1[j];  
        	}
        }  
        	//隐层和输出层之间的权值
        for(int i=0;i<L1;i++)
        {
        	Weight12[i][0]+=Step*Hide[i]*error2[0];  
        }
        return out;  
    }  
    public static double run(double i1,double i2,double i3,double i4,double i5)  
    {  
        double Hide[]=new double[L1];
        double out=0;  
        //计算隐层的输入
        for(int i=0;i<L1;i++)
        {
            Hide[i]=1*Threshold1[i]+i1*Weight01[0][i]+i2*Weight01[1][i]+i3*Weight01[2][i]+i4*Weight01[3][i]+i5*Weight01[4][i];
        }  
        //计算隐层的输出
        for(int i=0;i<L1;i++)
        {
            Hide[i]=transfer(Hide[i]);          	
        }
        //计算输出层的输入
        for(int i=0;i<L2;i++)
        {
        	for(int j=0;j<L1;j++)
        	{
        		out+=Hide[j]*Weight12[j][i];
        	}
        	out+=Threshold2[i];
        }
        //计算输出层的输出
        return transfer(out);  
    }  
    public static void print()  
    {  
        System.out.println("权值Weight01:");  
        for(int i=0;i<L0;i++)  
        {  
            for(int j=0;j<L1;j++)  
            {  
                System.out.print(Weight01[i][j]+"   ");  
            }  
            System.out.println();  
        }  
        System.out.println("权值Weight12:");  
        for(int i=0;i<L1;i++)  
        {  
            for(int j=0;j<L2;j++)  
            {  
                System.out.print(Weight12[i][j]+"   ");  
            }  
            System.out.println();  
        }  
        System.out.println("阈值Threshold1:");  
        for(int i=0;i<L1;i++)  
        {  
            System.out.print(Threshold1[i]+"    ");  
        }  
        System.out.println("\n阈值Threshold2:");  
        for(int i=0;i<L2;i++)  
        {  
            System.out.print(Threshold2[i]+"    ");  
        }  
        System.out.println("\n权值阈值打印完毕!");  
    }  
    public static void main(String[] args)   
    {  
        getData();  
        reflect();
        init();  
        for(int i=0;i<TrainTimes;i++)  
        {  
        	for(int j=0;j<M;j++)
        	{
        		train(Data[j][0],Data[j][1],Data[j][2],Data[j][3],Data[j][4],Data[j][5]); 
        	}
        }    
        double result=run(Data[5][0],Data[5][1],Data[5][2],Data[5][3],Data[5][4]);  
        result=result*(Max[5]-Min[5])+Min[5];  
        System.out.println("预测值:"+result);  
        double act=Data[5][5]*(Max[5]-Min[5])+Min[5];  
        System.out.println("实际值:"+act);       
    }  
}  

运行结果(未打印权值阈值,也未跟踪数据。如需要,可直接调用printData()函数):

预测值:1789.2462399023625
实际值:1790.0

----------------------------------------------------------------------------------------------------------------------------------------------------------

重新找数据进行验证网络的功能

参考书:陈志泊等。数据仓库与数据挖掘。北京:清华大学出版社,2009.5

                   P196。

1、修改记录条数M=9,字段个数N=5(3个输入,2个输出,分别训练和测试);输入层节点个数L0=3,隐层节点个数L1=7。

2、重写getData()函数,直接绑定数据。

 public static void getData() 
    {
    	Data[0][0]=19.96;
    	Data[0][1]=35.86;
    	Data[0][2]=8.27;
    	Data[0][3]=4.71;
    	Data[0][4]=19.96;
    	
    	Data[1][0]=19;
    	Data[1][1]=36.79;
    	Data[1][2]=8.54;
    	Data[1][3]=3.82;
    	Data[1][4]=19; 	
  	
    	Data[2][0]=20.06;
    	Data[2][1]=34.74;
    	Data[2][2]=8.06;
    	Data[2][3]=4.87;
    	Data[2][4]=20.06;
    	
    	Data[3][0]=18.72;
    	Data[3][1]=34.65;
    	Data[3][2]=8.22;
    	Data[3][3]=4.56;
    	Data[3][4]=18.72;
    	
    	Data[4][0]=20.42;
    	Data[4][1]=30.16;
    	Data[4][2]=7.04;
    	Data[4][3]=4.07;
    	Data[4][4]=20.42;	
    	
    	Data[5][0]=17.08;
    	Data[5][1]=34.22;
    	Data[5][2]=8.35;
    	Data[5][3]=3.68;
    	Data[5][4]=17.08;
    	
    	Data[6][0]=17.38;
    	Data[6][1]=36.41;
    	Data[6][2]=8.76;
    	Data[6][3]=3.84;
    	Data[6][4]=17.38;
    	
    	Data[7][0]=19.53;
    	Data[7][1]=35.72;
    	Data[7][2]=8.24;
    	Data[7][3]=3.97;
    	Data[7][4]=19.53;    	
    	
    	Data[8][0]=19.96;
    	Data[8][1]=36.09;
    	Data[8][2]=8.27;
    	Data[8][3]=4.32;
    	Data[8][4]=19.96;
    }

3、重写train()函数

修改函数的参数和输入层的内容即可

    public static double train(double i1 ,double i2,double i3,double d)  
    {  
    	double Input[]=new double[L0];//输入层单元
    	double Hide[]=new double[L1];//隐层单元    	
        double out=0;//输出层的输出  
        //设置输入层的数值
        Input[0]=i1;
        Input[1]=i2;
        Input[2]=i3;
……
}

其余部分不变。因为是下标控制的。

4、重写run()函数

 public static double run(double i1,double i2,double i3)  
    {  
        double Hide[]=new double[L1];
        double out=0;  
        //计算隐层的输入
        for(int i=0;i<L1;i++)
        {
            Hide[i]=1*Threshold1[i]+i1*Weight01[0][i]+i2*Weight01[1][i]+i3*Weight01[2][i];
        }  
        //计算隐层的输出
        for(int i=0;i<L1;i++)
        {
            Hide[i]=transfer(Hide[i]);          	
        }
        //计算输出层的输入
        for(int i=0;i<L2;i++)
        {
        	for(int j=0;j<L1;j++)
        	{
        		out+=Hide[j]*Weight12[j][i];
        	}
        	out+=Threshold2[i];
        }
        //计算输出层的输出
        return transfer(out);  
    }  

5、在main()函数中进行第1个输出的预测

 public static void main(String[] args)   
    {  
        getData();  
        printData();
        reflect();
        init();  
        System.out.print("训练并测试第1个输出\n");
        for(int i=0;i<TrainTimes;i++)  
        {  
         for(int j=0;j<M-1;j++)//训练前8个样本
         {
          train(Data[j][0],Data[j][1],Data[j][2],Data[j][3]); //注意期望输出是第4列
         }
        }    
        double result=run(Data[8][0],Data[8][1],Data[8][2]);  //测试第9个样本
        result=result*(Max[3]-Min[3])+Min[3];  
        System.out.println("预测值:"+result);  
        double act=Data[8][3]*(Max[3]-Min[3])+Min[3];  
        System.out.println("实际值:"+act);     
    }  

6、第1个测试的运行结果

训练并测试第1个输出
预测值:4.430013110096122
实际值:4.32

::::看来结果还是不错滴,哈哈~

7、在main()函数中进行第2个输出的预测

public static void main(String[] args)   
    {  
        getData();  
        printData();
        reflect();
        init();  
        System.out.print("训练并测试第2个输出\n");
        for(int i=0;i<TrainTimes;i++)  
        {  
         for(int j=0;j<M-1;j++)//训练前8个样本
         {
          train(Data[j][0],Data[j][1],Data[j][2],Data[j][4]); //注意期望输出是第5列
         }
        }    
        double result=run(Data[8][0],Data[8][1],Data[8][2]);  //测试第9个样本
        result=result*(Max[4]-Min[4])+Min[4];  
        System.out.println("预测值:"+result);  
        double act=Data[8][4]*(Max[4]-Min[4])+Min[4];  
        System.out.println("实际值:"+act);     
    }   

8、第2个测试的运行结果

训练并测试第2个输出
预测值:19.92995445524996
实际值:19.96

:::结果也是不错滴,第2次哈哈~


总结:

所有样本(包括用于测试的样本)进行归一化,取得最大值和最小值。

前8个样本参与训练,后一个样本参与测试。

测试的结果需要反归一化,反归一化需要该列的max和min,这些在归一化的过程中得到。实际值本身也参加的最大值和最小值的筛选。

 

为什么在这样的环境下就可以,在yx实际报上来的数据中运行就是不行呢??

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值