weka に基づくロジスティック回帰 (ロジスティック回帰) の手動実装

1. ロジスティック回帰モデル

ロジスティック回帰モデルは実際には分類モデルであり、ここでの実装は Li Hang 著の「Statistical Machine Learning」と Zhou Zhihua 著の「Machine Learning」の 2 冊の教科書に基づいています。

入力がxxであるとします。×××x は多次元にすることができ、xxxでyyを予測するyy ∈ { 0 , 1 } y\in \{0,1\}y{ 0 ,1 } . ロジスティックモデルは次のとおりです。

p ( Y = 1 ∣ x ) = exp ( w ⋅ x ) 1 + exp ( w ⋅ x ) (1) p(Y=1|x)=\frac{exp(w\cdot x)}{1+exp (w\cdot x)}\tag{1}p ( Y=1∣ x )=1+e x p ( w× e x p ( w×( 1 )

ここでパラメータwwwは学習したいものです。注: これには重み係数とバイアス (バイアス) b が含まれます。プログラムを作成する場合は、この表現の方が簡潔です。

第二に、最尤法パラメータ推定

パラメータwwwは学習する必要があるもので、最尤法を使用してモデル パラメーターを推定します。

設定:

P ( Y = 1 ∣ x ) = π ( x ) , P ( Y = 0 ∣ x ) = 1 − π ( x ) (2) P(Y=1|x)=\pi(x),\quad P (Y=0|x)=1-\pi(x)\tag{2}P ( Y)=1∣ x )=π ( x ) P ( Y)=0∣ x )=1π ( x )( 2 )

尤度関数は次のとおりです。

∏ i = 1 N [ π ( xi ) ] yi [ 1 − π ( xi ) ] 1 − yi (3) \prod_{i=1}^N[\pi(x_i)]^{y_i}[1-\ pi(x_i)]^{1-y_i} \tag{3}i = 1N[ p ( x私は) ]y私は[ 1π ( x私は) ]1 y私は( 3 )

この指数形式は導出に役立たないため、次のように対数形式に変換する必要があります。

L ( w ) = ∑ i = 1 N [ yilog π ( xi ) + ( 1 − yi ) log ( 1 − π ( xi ) ) ] = ∑ i = 1 N [ yilog ( π ( xi ) 1 − π ( xi ) ) ) + log ( 1 − π ( xi ) ) ] = ∑ i = 1 N [ yi ( w ⋅ xi ) − log ( 1 + exp ( w ⋅ xi ) ) ] (4) \begin{aligned} L(w )=&\sum_{i=1}^N[y_ilog\pi(x_i)+(1-y_i)log(1-\pi(x_i))] \\ =&\sum_{i=1}^N [ y_ilog(\frac{\pi(x_i)}{1-\pi(x_i)})+log(1-\pi(x_i))]\\ =&\sum_{i=1}^{N}[y_i (w\cdot x_i)-log(1+exp(w\cdot x_i))] \end{aligned} \tag{4}L ( w )===i = 1N[ y私はl o g π ( x私は)+( 1y私は) l o g ( 1π ( x私は))]i = 1N[ y私はl o g (1π ( x私は)π ( x私は))+l o g ( 1π ( x私は))]i = 1N[ y私は( wバツ私は)l o g ( 1+e x p ( wバツ私は)) ]( 4 )

L ( w )の場合L(w)L ( w )の最大値を見つけてwwwの推定値

第三に、尤度関数を解くための勾配降下法

勾配降下法は最小値を見つけることであり、取得したいのはL ( w ) L(w)です。L ( w )の最大値、したがって、L ( w ) L(w)L ( w )の反対の数、つまり:

arg min ⁡ w − L ( w ) (5) \argmin_{w}-L(w) \tag{5}w引数L ( w )( 5 )

L ( w )の場合L(w)L(w)关于 w w wの微分は

( − L ( w ) ) ′ = − ∑ i = 1 N [ ( yi ⋅ xi ) − exp ( w ⋅ xi ) 1 + exp ( w ⋅ x ) ⋅ xi ] = − ∑ i = 1 N [ ( yi − exp ( w ⋅ xi ) 1 + exp ( w ⋅ x ) ) ⋅ xi ] = ∑ i = 1 N [ ( exp ( w ⋅ xi ) 1 + exp ( w ⋅ x ) − yi ) ⋅ xi ] (6) \ begin{aligned} (-L(w))'=&-\sum_{i=1}^N[(y_i\cdot x_i)-\frac{exp(w\cdot x_i)}{1+exp(w\ cdot x)}\cdot x_i]\\ =&-\sum_{i=1}^N[(y_i-\frac{exp(w\cdot x_i)}{1+exp(w\cdot x)})\ cdot x_i]\\ =&\sum_{i=1}^N[(\frac{exp(w\cdot x_i)}{1+exp(w\cdot x)}-y_i)\cdot x_i] \end{整列} \tag{6}( L ( w ) )===i = 1N[( y私はバツ私は)1+e x p ( w× e x p ( wバツ私は)バツ私は]i = 1N[( y私は1+e x p ( w× e x p ( wバツ私は))バツ私は]i = 1N[(1+e x p ( w× e x p ( wバツ私は)y私は)バツ私は]( 6 )

次にパラメータを取得しますwwwの更新式は次のとおりです。

w ′ = w − lr ⋅ ( − L ( w ) ′ ) = w − lr ⋅ ( ∑ i = 1 N [ ( exp ( w ⋅ xi ) 1 + exp ( w ⋅ x ) − yi ) ⋅ xi ] ) ( 7) \begin{aligned} w'=&w-lr\cdot(-L(w)')\\ =&w-lr\cdot(\sum_{i=1}^N[(\frac{exp(w\ cdot x_i)}{1+exp(w\cdot x)}-y_i)\cdot x_i]) \end{aligned} \tag{7}w==wl r( L ( w ) _wl r(i = 1N[(1+e x p ( w× e x p ( wバツ私は)y私は)バツ私は] )( 7 )

最適化手法の選択については、当初はスイカ本に掲載されているニュートン法を選択しましたが、ニュートン法の利点はより速い収束速度が得られることですが、欠点はヘッセ行列が特異行列が表示されます。解決できないケースが表示されます。

したがって、準ニュートン法を最適化に使用することができ、この問題を解決しながらも高速に収束することができます。

ただし、準ニュートン法には詳しくありません。また、勾配降下法は収束が遅いかもしれませんが、実装は比較的簡単であるため、ここでは尤度関数の最適化に勾配降下法を使用します。

4 番目、weka ベースのコード実装

package weka.classifiers.myf;

import weka.classifiers.Classifier;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.matrix.Matrix;
import weka.filters.Filter;
import weka.filters.unsupervised.attribute.NominalToBinary;
import weka.filters.unsupervised.attribute.Standardize;

import java.util.Arrays;

/**
 * @author YFMan
 * @Description 自定义的 Logistic 回归分类器
 * @Date 2023/6/13 11:02
 */
public class myLogistic extends Classifier {
    
    
    // 用于存储 线性回归 系数 的数组
    private double[] m_Coefficients;

    // 类别索引
    private int m_ClassIndex;

    // 牛顿法的迭代次数
    private int m_MaxIterations = 1000;

    // 属性数量
    private int m_numAttributes;

    // 系数数量
    private int m_numCoefficients;

    // 梯度下降步长
    private double m_lr = 1e-4;

    // 标准化数据的过滤器
    public static final int FILTER_STANDARDIZE = 1;

    // 用于标准化数据的过滤器
    protected Filter m_StandardizeFilter = null;

    // 用于将 normal 转为 binary 的过滤器
    protected Filter m_NormalToBinaryFilter = null;


    /*
     * @Author YFMan
     * @Description 采用牛顿法来训练 logistic 回归模型
     * @Date 2023/5/9 22:08
     * @Param [data] 训练数据
     * @return void
     **/
    public void buildClassifier(Instances data) throws Exception {
    
    
        // 设置类别索引
        m_ClassIndex = data.classIndex();

        // 设置属性数量
        m_numAttributes = data.numAttributes();

        // 系数数量 = 输入属性数量 + 1(截距参数b)
        m_numCoefficients = m_numAttributes;

        // 初始化 系数数组
        m_Coefficients = new double[m_numCoefficients];
        Arrays.fill(m_Coefficients, 0);

        // 将输入数据进行标准化
        m_StandardizeFilter = new Standardize();
        m_StandardizeFilter.setInputFormat(data);
        data = Filter.useFilter(data, m_StandardizeFilter);

        // 将类别属性转为二值属性
        m_NormalToBinaryFilter = new NominalToBinary();
        m_NormalToBinaryFilter.setInputFormat(data);
        data = Filter.useFilter(data, m_NormalToBinaryFilter);

        // 梯度下降法
        for(int curPerformIteration = 0; curPerformIteration < m_MaxIterations;curPerformIteration++){
    
    

            double[] deltaM_Coefficients = new double[m_numCoefficients];
            // 计算 l(w) 的一阶导数
            for(int i = 0;i<data.numInstances();i++){
    
    

                double yi = data.instance(i).value(m_ClassIndex);
                double wxi = 0;
                int column = 0;
                for(int j=0;j<m_numAttributes;j++){
    
    
                    if(j!=m_ClassIndex){
    
    
                        wxi += m_Coefficients[column] * data.instance(i).value(j);
                        column++;
                    }
                }
                // 加上截距参数 b
                wxi += m_Coefficients[column];
                double pi1 = Math.exp(wxi) / (1 + Math.exp(wxi));
                for(int k=0;k<m_numCoefficients - 1;k++){
    
    
                    deltaM_Coefficients[k] += m_lr * (pi1 - yi) * data.instance(i).value(k);
                }
                // 这里计算 bias b 对应的更新量
                deltaM_Coefficients[m_numCoefficients - 1] += m_lr * (pi1 - yi);
            }

            // 进行参数更新
            for(int k=0;k<m_numCoefficients;k++){
    
    
                m_Coefficients[k] -= deltaM_Coefficients[k];
            }

            // 如果参数更新量小于阈值,则停止迭代
            double delta = 0;
            for(int k=0;k<m_numCoefficients;k++){
    
    
                delta += deltaM_Coefficients[k] * deltaM_Coefficients[k];
            }
            if(delta < 1e-6){
    
    
                break;
            }

        }
    }


    /*
     * @Author YFMan
     * @Description // 分类实例
     * @Date 2023/6/16 11:17
     * @Param [instance]
     * @return double[]
     **/
    public double[] distributionForInstance(Instance instance) throws Exception {
    
    

        // 将输入数据进行标准化
        m_StandardizeFilter.input(instance);
        instance = m_StandardizeFilter.output();

        // 将输入属性二值化
        m_NormalToBinaryFilter.input(instance);
        instance = m_NormalToBinaryFilter.output();

        double[] result = new double[2];
        result[0] = 0;
        result[1] = 0;
        int column = 0;
        for(int i=0;i<m_numAttributes;i++){
    
    
            if(m_ClassIndex != i){
    
    
                result[0] += instance.value(i) * m_Coefficients[column];
                column++;
            }
        }
        result[0] += m_Coefficients[column];
        result[0] = 1 / (1 + Math.exp(result[0]));

        result[1] = 1 - result[0];

        return result;
    }

    /*
     * @Author YFMan
     * @Description 主函数 生成一个线性回归函数预测器
     * @Date 2023/5/9 22:35
     * @Param [argv]
     * @return void
     **/
    public static void main(String[] argv) {
    
    
        runClassifier(new myLogistic(), argv);
    }
}

おすすめ

転載: blog.csdn.net/myf_666/article/details/131253958