Python 如何为catboost创建自定义评估指标?

Python 如何为catboost创建自定义评估指标?,python,scikit-learn,catboost,Python,Scikit Learn,Catboost,类似问题: Catboost教程 问题: 在这个问题中,我有一个二进制分类问题。建模后,我们得到了测试模型预测,我们已经有了真正的测试标签 我想获得由以下等式定义的自定义评估指标: profit = 400 * truePositive - 200*fasleNegative - 100*falsePositive 另外,由于利润越高越好,我希望最大化函数,而不是最小化函数 如何在catboost中获取此评估度量 使用sklearn def get_price(y_true,y_p

类似问题:

Catboost教程

问题: 在这个问题中,我有一个二进制分类问题。建模后,我们得到了测试模型预测,我们已经有了真正的测试标签

我想获得由以下等式定义的自定义评估指标:

profit = 400 * truePositive - 200*fasleNegative - 100*falsePositive
另外,由于利润越高越好,我希望最大化函数,而不是最小化函数

如何在catboost中获取此评估度量

使用sklearn
def get_price(y_true,y_pred):
tn,fp,fn,tp=sklearn.metrics.conflusion\u矩阵(y\u true,y\u pred).ravel()
损耗=400*tp-200*fn-100*fp
回波损耗
scoring=sklearn.metrics.make_scorer(获得利润,越大越好=真)
使用catboost
class ProfitMetric(对象):
def get_最终_错误(自身、错误、重量):
返回错误/(重量+1e-38)
def是_max_最优(自):
返回真值
def评估(自我、接近、目标、重量):
断言len(近似)==1
断言len(目标)=len(接近[0])
近似值=近似值[0]
误差_和=0.0
权重总和=0.0
**我在这里不知道**
返回错误\u和,权重\u和
问题: 如何在catboost中完成自定义评估指标

更新 到目前为止我的更新

将numpy导入为np
作为pd进口熊猫
导入seaborn作为sns
导入sklearn
从catboost导入CatBoostClassifier
从sklearn.model\u选择导入列车\u测试\u拆分
def获取利润(y_真,y_pred):
tn,fp,fn,tp=sklearn.metrics.conflusion\u矩阵(y\u true,y\u pred).ravel()
利润=400*tp-200*fn-100*fp
利润回报
等级ProfitMetric:
def是_max_最优(自):
返回真值#越大越好
def评估(自我、接近、目标、重量):
断言len(近似)==1
断言len(目标)=len(接近[0])
近似值=近似值[0]
y_pred=np.rint(近似值)
y_true=np.array(target).astype(int)
输出重量=1#未使用重量
得分=获得利润(y_真,y_pred)
返回分数、输出值和权重
def get_最终_错误(自身、错误、重量):
返回错误
df=sns.load_数据集(“泰坦尼克号”)
X=df[[‘幸存’、‘等级’、‘年龄’、‘sibsp’、‘票价’]
y=X.pop('幸存')
X_序列,X_测试,y_序列,y_测试=序列测试分割(X,y,测试大小=0.2,随机状态=100)
型号=CatBoostClassifier(公制周期=50,
n_估计量=200,
eval_metric=ProfitMetric()
)
model.fit(X,y,eval_set=(X_test,y_test))#此操作失败

作为示例,我实现了一个非常简单的度量

它计算y_pred!=在多类分类器中为真

class CountErrors:
    '''Count of wrong predictions'''
    
    def is_max_optimal(self):
        False

    def evaluate(self, approxes, target, weight):  
        
        y_pred = np.array(approxes).argmax(0)
        y_true = np.array(target)
                                    
        return sum(y_pred!=y_true), 1

    def get_final_error(self, error, weight):
        return error
如果运行以下代码,您可以看到它已被使用:

import numpy as np
import pandas as pd

from catboost import CatBoostClassifier
from sklearn.model_selection import train_test_split

class CountErrors:
    '''Count number of wrong predictions'''
    
    def is_max_optimal(self):
        False # Lower is better

    def evaluate(self, approxes, target, weight):  
        
        y_pred = np.array(approxes).argmax(0)
        y_true = np.array(target)
                                    
        return sum(y_pred!=y_true), 1

    def get_final_error(self, error, weight):
        return error
    

df = pd.read_csv('https://raw.githubusercontent.com/mkleinbort/resource-datasets/master/abalone/abalone.csv')
y = df['sex']
X = df.drop(columns=['sex'])

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=12)

model = CatBoostClassifier(metric_period=50, n_estimators=200, eval_metric=CountErrors())

model.fit(X, y, eval_set=(X_test, y_test))

希望您能根据您的用例调整此选项。

与您的主要区别在于:

@staticmethod
def get_profit(y_true, y_pred):
    y_pred = expit(y_pred).astype(int)
    y_true = y_true.astype(int)
    #print("ACCURACY:",(y_pred==y_true).mean())
    tn, fp, fn, tp = confusion_matrix(y_true, y_pred).ravel()
    loss = 400*tp - 200*fn - 100*fp
    return loss
从you linked上看不出预测是什么,但检查后发现,
catboost
将预测内部视为原始对数概率(hat tip@Ben)。因此,要正确使用
混淆矩阵
,您需要确保
y\u true
y\u pred
都是整数类标签。这是通过以下方式实现的:

y_pred = scipy.special.expit(y_pred) 
y_true = y_true.astype(int)
因此,完整的工作代码是:

import seaborn as sns
from catboost import CatBoostClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
from scipy.special import expit

df = sns.load_dataset('titanic')
X = df[['survived','pclass','age','sibsp','fare']]
y = X.pop('survived')

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=100)

class ProfitMetric:
    
    @staticmethod
    def get_profit(y_true, y_pred):
        y_pred = expit(y_pred).astype(int)
        y_true = y_true.astype(int)
        #print("ACCURACY:",(y_pred==y_true).mean())
        tn, fp, fn, tp = confusion_matrix(y_true, y_pred).ravel()
        loss = 400*tp - 200*fn - 100*fp
        return loss
    
    def is_max_optimal(self):
        return True # greater is better

    def evaluate(self, approxes, target, weight):            
        assert len(approxes) == 1
        assert len(target) == len(approxes[0])
        y_true = np.array(target).astype(int)
        approx = approxes[0]
        score = self.get_profit(y_true, approx)
        return score, 1

    def get_final_error(self, error, weight):
        return error

model = CatBoostClassifier(metric_period=50,
  n_estimators=200,
  eval_metric=ProfitMetric()
)

model.fit(X, y, eval_set=(X_test, y_test))

这是伟大的和工程,但我正在寻找一种方法来获得自定义分数的二进制分类。这应该与二进制分类。尝试将此行替换为:
return sum(y_pred!=y_true),1
与您的自定义度量值您链接了用于培训的自定义损失和仅用于评估且不影响培训的评估度量值。您对哪一个感兴趣?@SergeyBushmanov原始数据集是关于客户流失的,我定义了自定义指标,该指标根据二元分类的TP、TN、FP、FN计算“利润”。我想直接优化指标“利润”而不是“auc”,如何在catboost中实现?评估指标不会影响培训。如果你想让你的培训优化(最大化)你的定制指标,你需要(1)为你的函数写一个梯度和hess来优化,或者(2)找到一个现成的,可以紧密复制的yours@SergeyBushmanov好的,我明白了。然后,我只想得到带有默认损失函数的eval度量。不过,我的评估指标不起作用。如果您通过示例进行指导,我将非常感谢您的努力。这非常完美。我做了
打印(model.get\u evals\u result())
这给了我利润。非常感谢。你可以考虑接受☺既然你已经有了混乱矩阵,为什么还要循环?@BenReiniger更新了!如果我们做了列表解包,它就不起作用了(
tn,fp,fn,tp=composition\u matrix(y\u true,y\u pred).ravel()不起作用
)。只有for循环有效。