[PYTHON] Scikit을 사용하여 특정 클래스 예측에 대한 각 기능의 기여도 결정
PYTHONScikit을 사용하여 특정 클래스 예측에 대한 각 기능의 기여도 결정
나는 scikit 여분 나무 분류자를 사용하고있다 :
model = ExtraTreesClassifier(n_estimators=10000, n_jobs=-1, random_state=0)
모델이 클래스를 예측하는 데 적합하고 사용되면, 특정 클래스 예측에 대한 각 기능의 기여도를 확인하고자합니다. scikit에서 어떻게 배우나요? 여분의 나무 분류기로 가능합니까 아니면 다른 모델을 사용해야합니까?
해결법
-
==============================
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.문서에서 수정되었습니다.
문서에서 수정되었습니다.
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.종이 "왜 당신을 신뢰해야합니까?":이 문제에 대한 일반적인 해결책을 제공하는 알고리즘을 제공하여이 질문 후 9 일 후에 모든 분류 자의 예측을 설명했습니다! :-)
종이 "왜 당신을 신뢰해야합니까?":이 문제에 대한 일반적인 해결책을 제공하는 알고리즘을 제공하여이 질문 후 9 일 후에 모든 분류 자의 예측을 설명했습니다! :-)
즉, "해석 가능한 지역 모델에 대한 설명"을 위해 LIME이라고하며, 이해하려는 예측에 대해보다 단순한 지역 모델을 적용하여 작동합니다.
게다가, 그들은 sklearn과 함께 사용하는 방법에 대한 아주 상세한 예제를 가지고 파이썬 구현 (https://github.com/marcotcr/lime)을 만들었습니다. 예를 들어, 이것은 텍스트 데이터에 대한 2 등급 임의의 포레스트 문제에 관한 것이며,이 것은 연속적이고 범주적인 특징에 관한 것입니다. 그들은 모두 github에있는 README를 통해 찾을 수 있습니다.
저자는이 분야와 관련하여 2016 년에 매우 생산적인 해를 보았습니다. 따라서 논문을 읽는 것을 좋아한다면 여기에 초보자가 있습니다.
-
==============================
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에서 도우미 노트북.
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
'PYTHON' 카테고리의 다른 글
[PYTHON] 트위스트 conch 파일 전송 (0) | 2018.10.24 |
---|---|
[PYTHON] python3에서 프로그램의 표준 입력으로 보내기 3 (0) | 2018.10.24 |
[PYTHON] Scrapy : spider_idle 이벤트 콜백에서 요청을 수동으로 삽입하는 방법은 무엇입니까? (0) | 2018.10.24 |
[PYTHON] 파이썬 : mechanize.Browser 인스턴스의 쿠키를 버리는 법? (0) | 2018.10.24 |
[PYTHON] 아파치 2에서 파이썬 스크립트 실행하기 (0) | 2018.10.24 |