복붙노트

[PYTHON] Scikit을 사용하여 특정 클래스 예측에 대한 각 기능의 기여도 결정

PYTHON

Scikit을 사용하여 특정 클래스 예측에 대한 각 기능의 기여도 결정

나는 scikit 여분 나무 분류자를 사용하고있다 :

model = ExtraTreesClassifier(n_estimators=10000, n_jobs=-1, random_state=0)

모델이 클래스를 예측하는 데 적합하고 사용되면, 특정 클래스 예측에 대한 각 기능의 기여도를 확인하고자합니다. scikit에서 어떻게 배우나요? 여분의 나무 분류기로 가능합니까 아니면 다른 모델을 사용해야합니까?

해결법

  1. ==============================

    1.2.5 년 전보다 오늘날 ML에 대해 더 많이 알고 있기 때문에,이 접근법은 고도의 선형 의사 결정 문제에서만 작동한다고 말할 것입니다. 부주의하게 비선형 문제에 적용하면 문제가 발생할 것입니다.

    2.5 년 전보다 오늘날 ML에 대해 더 많이 알고 있기 때문에,이 접근법은 고도의 선형 의사 결정 문제에서만 작동한다고 말할 것입니다. 부주의하게 비선형 문제에 적용하면 문제가 발생할 것입니다.

    예 : 매우 크지도 작은 값도 클래스를 예측하지는 않지만 일부 중간 간격의 값은 예측하지 않는 기능을 상상해보십시오. 그것은 탈수를 예측하기위한 물 섭취량 일 수 있습니다. 그러나 물 섭취는 아마도 소금 섭취와 상호 작용합니다. 소금 섭취가 많을수록 섭취량이 많아집니다. 이제 두 개의 비선형 피처 사이에 상호 작용이 있습니다. 의사 결정 경계는이 비선형 성을 모델링하고 기능 중 탈수증의 위험에 얼마나 많은 영향을 미치는지 묻기 만하면 기능 공간을 우회합니다. 올바른 질문이 아닙니다.

    대안 : 당신이 물을 수있는 또 다른 의미있는 질문은 다음과 같습니다.이 정보가 없으면 (예 :이 기능을 생략 한 경우) 주어진 라벨에 대한 내 예측이 얼마나 어려울 수 있습니까? 이를 위해 단순히 기능을 생략하고 모델을 훈련하며 각 클래스에 대해 얼마나 정밀도를 측정하고 드롭을 리콜합니다. 여전히 기능의 중요성에 대해 알려주지 만 선형성에 대한 가정은하지 않습니다.

    아래는 이전 답변입니다.

    나는 비슷한 질문을하면서 잠시 후 Cross Validated에 같은 질문을 게시했다. 짧은 대답은 sklearn에 구현이 없다는 것입니다.

    그러나 달성하려는 것은 실제로 매우 간단하며 각 클래스에서 각 기능 분할의 평균 표준화 평균 값에 해당하는 model._feature_importances 배열 요소를 곱하여 수행 할 수 있습니다. 데이터 집합을 표준화하고 클래스 예측을 통해 분할 된 각 피쳐의 평균을 계산하며 model._feature_importances 배열을 사용하여 요소 단위의 곱셈을 수행하는 간단한 함수를 작성할 수 있습니다. 절대 결과 값이 클수록 기능이 예상되는 클래스에 더 중요하며 더 중요한 것은 작거나 큰 값이 중요한지 여부를 알려주는 기호입니다.

    다음은 데이터 매트릭스 X, 예측 Y 목록 및 피쳐 가져 오기 배열을 취하고 각 피쳐의 중요성을 설명하는 JSON을 각 클래스에 출력하는 간단한 간단한 구현입니다.

    def class_feature_importance(X, Y, feature_importances):
        N, M = X.shape
        X = scale(X)
    
        out = {}
        for c in set(Y):
            out[c] = dict(
                zip(range(N), np.mean(X[Y==c, :], axis=0)*feature_importances)
            )
    
        return out
    

    예:

    import numpy as np
    import json
    from sklearn.preprocessing import scale
    
    X = np.array([[ 2,  2,  2,  0,  3, -1],
                  [ 2,  1,  2, -1,  2,  1],
                  [ 0, -3,  0,  1, -2,  0],
                  [-1, -1,  1,  1, -1, -1],
                  [-1,  0,  0,  2, -3,  1],
                  [ 2,  2,  2,  0,  3,  0]], dtype=float)
    
    Y = np.array([0, 0, 1, 1, 1, 0])
    feature_importances = np.array([0.1, 0.2, 0.3, 0.2, 0.1, 0.1])
    #feature_importances = model._feature_importances
    
    result = class_feature_importance(X, Y, feature_importances)
    
    print json.dumps(result,indent=4)
    
    {
        "0": {
            "0": 0.097014250014533204, 
            "1": 0.16932975630904751, 
            "2": 0.27854300726557774, 
            "3": -0.17407765595569782, 
            "4": 0.0961523947640823, 
            "5": 0.0
        }, 
        "1": {
            "0": -0.097014250014533177, 
            "1": -0.16932975630904754, 
            "2": -0.27854300726557779, 
            "3": 0.17407765595569782, 
            "4": -0.0961523947640823, 
            "5": 0.0
        }
    }
    

    결과의 키의 첫 번째 수준은 클래스 레이블이며 키의 두 번째 수준은 열 인덱스, 즉 지형지 물 인덱스입니다. 큰 절대 값은 중요도에 해당하며 기호는 중요하지 않은 작은 값 (음수 일 수도 있음) 또는 큰 값인지 여부를 알려줍니다.

  2. ==============================

    2.문서에서 수정되었습니다.

    문서에서 수정되었습니다.

    from sklearn import datasets
    from sklearn.ensemble import ExtraTreesClassifier
    
    iris = datasets.load_iris()  #sample data
    X, y = iris.data, iris.target
    
    model = ExtraTreesClassifier(n_estimators=10000, n_jobs=-1, random_state=0)
    model.fit_transform(X,y) # fit the dataset to your model
    

    나는 feature_importances_가 당신이 찾고있는 것이라고 생각합니다 :

    In [13]: model.feature_importances_
    Out[13]: array([ 0.09523045,  0.05767901,  0.40150422,  0.44558631])
    

    편집하다

    어쩌면 내가 처음으로 오해 한 것입니다 (선매 특전), 죄송합니다, 이것은 당신이 찾고있는 라인을 따라 더 많을 수 있습니다. Treeinterpreter라는 파이썬 라이브러리가 있는데, 당신이 찾고 있다고 생각하는 정보를 생성합니다. 기본 DecisionTreeClassifer (또는 Regressor)를 사용해야합니다. 이 블로그 게시물을 따라 가면서 각 인스턴스의 예측에서 기능 기여에 개별적으로 액세스 할 수 있습니다.

    from sklearn import datasets
    from sklearn.cross_validation import train_test_split
    from sklearn.tree import DecisionTreeClassifier
    
    from treeinterpreter import treeinterpreter as ti
    
    iris = datasets.load_iris()  #sample data
    X, y = iris.data, iris.target
    #split into training and test 
    X_train, X_test, y_train, y_test = train_test_split( 
        X, y, test_size=0.33, random_state=0)
    
    # fit the model on the training set
    model = DecisionTreeClassifier(random_state=0)
    model.fit(X_train,y_train)
    

    설명을 위해 X_test의 각 샘플을 반복 해 보겠습니다. 위의 블로그 게시물을 거의 정확히 모방합니다.

    for test_sample in range(len(X_test)):
        prediction, bias, contributions = ti.predict(model, X_test[test_sample].reshape(1,4))
        print "Class Prediction", prediction
        print "Bias (trainset prior)", bias
    
        # now extract contributions for each instance
        for c, feature in zip(contributions[0], iris.feature_names):
            print feature, c
    
        print '\n'
    

    루프의 첫 번째 반복은 다음을 산출합니다.

    Class Prediction [[ 0.  0.  1.]]
    Bias (trainset prior) [[ 0.34  0.31  0.35]]
    sepal length (cm) [ 0.  0.  0.]
    sepal width (cm) [ 0.  0.  0.]
    petal length (cm) [ 0.         -0.43939394  0.43939394]
    petal width (cm) [-0.34        0.12939394  0.21060606]
    

    이 결과를 해석해 보면, 꽃잎 길이와 꽃잎 너비가 (첫 번째 샘플의 경우) 3 등급 예측에 가장 중요한 요인이었던 것처럼 보입니다. 희망이 도움이됩니다.

  3. ==============================

    3.종이 "왜 당신을 신뢰해야합니까?":이 문제에 대한 일반적인 해결책을 제공하는 알고리즘을 제공하여이 질문 후 9 일 후에 모든 분류 자의 예측을 설명했습니다! :-)

    종이 "왜 당신을 신뢰해야합니까?":이 문제에 대한 일반적인 해결책을 제공하는 알고리즘을 제공하여이 질문 후 9 일 후에 모든 분류 자의 예측을 설명했습니다! :-)

    즉, "해석 가능한 지역 모델에 대한 설명"을 위해 LIME이라고하며, 이해하려는 예측에 대해보다 단순한 지역 모델을 적용하여 작동합니다.

    게다가, 그들은 sklearn과 함께 사용하는 방법에 대한 아주 상세한 예제를 가지고 파이썬 구현 (https://github.com/marcotcr/lime)을 만들었습니다. 예를 들어, 이것은 텍스트 데이터에 대한 2 등급 임의의 포레스트 문제에 관한 것이며,이 것은 연속적이고 범주적인 특징에 관한 것입니다. 그들은 모두 github에있는 README를 통해 찾을 수 있습니다.

    저자는이 분야와 관련하여 2016 년에 매우 생산적인 해를 보았습니다. 따라서 논문을 읽는 것을 좋아한다면 여기에 초보자가 있습니다.

  4. ==============================

    4.지금까지 나는 eli5와 treeinterpreter (둘 다 전에 언급 했음)를 확인해 왔으며 eli5가 더 많은 도움이 될 것이라고 생각합니다. 왜냐하면 더 많은 옵션이 있고 더 일반적이고 업데이트 된 것으로 생각하기 때문입니다.

    지금까지 나는 eli5와 treeinterpreter (둘 다 전에 언급 했음)를 확인해 왔으며 eli5가 더 많은 도움이 될 것이라고 생각합니다. 왜냐하면 더 많은 옵션이 있고 더 일반적이고 업데이트 된 것으로 생각하기 때문입니다.

    그럼에도 불구하고 특정 기간 동안 eli5를 적용한 후 ExtraTreesClassifier에 대한 부정적인 기여를 얻지 못했습니다. 조금 더 연구하면서 여기에서 볼 수있는 중요성이나 중요성을 얻고 있다는 것을 깨달았습니다. 이 질문의 제목에 언급 된 것처럼 기고와 같은 것에 더 관심이 있었기 때문에 일부 기능이 부정적인 영향을 미칠 수 있음을 이해하지만 중요성을 측정 할 때는 기호가 중요하지 않으므로 긍정적 인 효과와 제외 효과가있는 기능이 결합되었습니다.

    나는 내가 다음과 같이 서명 한 것에 매우 흥미가 있었기 때문에 : 1) 모든 경우에 대한 기여도를 얻는다. 2) 동일한 결과를 구별 할 수있는 모든 결과를 합의하십시오. 매우 우아한 솔루션이 아닙니다. 아마 거기에 더 나은 것이 있습니다. 도움이 될 수 있도록 여기에 게시합니다.

    이전 게시물과 동일한 것을 재현합니다.

    from sklearn import datasets
    from sklearn.cross_validation import train_test_split
    from sklearn.tree import DecisionTreeClassifier
    from sklearn.ensemble import  (ExtraTreesClassifier, RandomForestClassifier, 
                                  AdaBoostClassifier, GradientBoostingClassifier)
    import eli5
    
    
    iris = datasets.load_iris()  #sample data
    X, y = iris.data, iris.target
    #split into training and test 
    X_train, X_test, y_train, y_test = train_test_split( 
        X, y, test_size=0.33, random_state=0)
    
    # fit the model on the training set
    #model = DecisionTreeClassifier(random_state=0)
    model = ExtraTreesClassifier(n_estimators= 100)
    
    model.fit(X_train,y_train)
    
    
    aux1 = eli5.sklearn.explain_prediction.explain_prediction_tree_classifier(model,X[0], top=X.shape[1])
    
    aux1
    

    산출물과 함께

    이전 결과는 모두 실행하고 평균을 작성하려는 경우로 작동합니다.

    다음은 결과가있는 데이터 프레임의 모습입니다.

    aux1 = eli5.sklearn.explain_prediction.explain_prediction_tree_classifier(model,X[0], top=X.shape[0])
    aux1 = eli5.format_as_dataframe(aux1)
    # aux1.index = aux1['feature']
    # del aux1['target']
    aux
    
    
    target  feature weight  value
    0   0   <BIAS>  0.340000    1.0
    1   0   x3  0.285764    0.2
    2   0   x2  0.267080    1.4
    3   0   x1  0.058208    3.5
    4   0   x0  0.048949    5.1
    5   1   <BIAS>  0.310000    1.0
    6   1   x0  -0.004606   5.1
    7   1   x1  -0.048211   3.5
    8   1   x2  -0.111974   1.4
    9   1   x3  -0.145209   0.2
    10  2   <BIAS>  0.350000    1.0
    11  2   x1  -0.009997   3.5
    12  2   x0  -0.044343   5.1
    13  2   x3  -0.140554   0.2
    14  2   x2  -0.155106   1.4
    

    그래서 이전 종류의 테이블을 결합하는 함수를 만듭니다.

    def concat_average_dfs(aux2,aux3):
        # Putting the same index together
    #     I use the try because I want to use this function recursive and 
    #     I could potentially introduce dataframe with those indexes. This
    #     is not the best way.
        try:
            aux2.set_index(['feature', 'target'],inplace = True)
        except:
            pass
        try:
            aux3.set_index(['feature', 'target'],inplace = True)
        except:
            pass
        # Concatenating and creating the meand
        aux = pd.DataFrame(pd.concat([aux2['weight'],aux3['weight']]).groupby(level = [0,1]).mean())
        # Return in order
        #return aux.sort_values(['weight'],ascending = [False],inplace = True)
        return aux
    aux2 = aux1.copy(deep=True)
    aux3 = aux1.copy(deep=True)
    
    concat_average_dfs(aux3,aux2)
    

    그래서 이제는 원하는 모든 예제와 함께 이전 함수 만 사용해야합니다. 나는 훈련 세트뿐만 아니라 전체 인구를 데려 갈 것이다. 모든 실제 사례의 평균 효과 확인

    for i in range(X.shape[0]):
    
    
        aux1 = eli5.sklearn.explain_prediction.explain_prediction_tree_classifier(model,X\[i\], top=X.shape\[0\])
        aux1 = eli5.format_as_dataframe(aux1)
    
        if 'aux_total'  in locals() and 'aux_total' in  globals():
            aux_total = concat_average_dfs(aux1,aux_total)
        else:
            aux_total = aux1
    

    결과 :

    Las 테이블은 모든 실제 인구에 대한 각 기능의 평균 효과를 보여줍니다.

    내 github에서 도우미 노트북.

  5. from https://stackoverflow.com/questions/35249760/using-scikit-to-determine-contributions-of-each-feature-to-a-specific-class-pred by cc-by-sa and MIT license