CatBoostRegressor 树中叶值的比例是多少?
What is the scale of the leaf values in a CatBoostRegressor tree?
谜题
我无法解释 CatBoostRegressor
树的叶子中的值。拟合模型正确地捕获了数据集的逻辑,但是当我绘制树图时值的比例与实际数据集的比例不匹配。
在此示例中,我们预测 size
,其值约为 15-30,具体取决于观察的 color
和 age
。
import random
import pandas as pd
import numpy as np
from catboost import Pool, CatBoostRegressor
# Create a fake dataset.
n = 1000
random.seed(1)
df = pd.DataFrame([[random.choice(['red', 'blue', 'green', 'yellow']),
random.random() * 100]
for i in range(n)],
columns=['color', 'age'])
df['size'] = np.select([np.logical_and(np.logical_or(df.color == 'red',
df.color == 'blue'),
df.age < 50),
np.logical_or(df.color == 'red',
df.color == 'blue'),
df.age < 50,
True],
[np.random.normal(loc=15, size=n),
np.random.normal(loc=20, size=n),
np.random.normal(loc=25, size=n),
np.random.normal(loc=30, size=n)])
# Fit a CatBoost regressor to the dataset.
pool = Pool(df[['color', 'age']], df['size'],
feature_names=['color', 'age'], cat_features=[0])
m = CatBoostRegressor(n_estimators=10, max_depth=3, one_hot_max_size=4,
random_seed=1)
m.fit(pool)
# Visualize the first regression tree (saves to a pdf). Values in leaf nodes
# are not on the scale of the original dataset.
m.plot_tree(tree_idx=0, pool=pool).render('regression_tree')
模型在 age
上以正确的值(大约 50)拆分,并且它正确地了解到红色和蓝色观察值不同于绿色和黄色观察值。叶子中的值排序正确(例如,red/blue 50 以下的观测值最小),但比例完全不同。
predict()
函数 returns 原始数据集规模上的值。
>>> df['predicted'] = m.predict(df)
>>> df.sample(n=10)
color age size predicted
676 yellow 66.305095 30.113389 30.065519
918 yellow 55.209821 29.944622 29.464825
705 yellow 1.742565 24.209283 24.913988
268 blue 76.749979 20.513211 20.019020
416 blue 59.807800 18.807197 19.949336
326 red 4.621795 14.748898 14.937314
609 yellow 99.165027 28.942243 29.823422
421 green 40.731038 26.078450 24.846742
363 yellow 2.461971 25.506517 24.913988
664 red 5.206448 16.579706 14.937314
我试过的
我想知道是否正在进行某种简单的规范化,但事实显然并非如此。例如,年龄 < 50 的红色观察值在树中被指定为 -3.418,这与真实值的 z 分数(大约 15)相去甚远。
>>> (15 - np.mean(df['size'])) / np.std(df['size'])
-1.3476124913754326
问了一个关于 XGBoost 的类似问题。接受的答案解释说,这些值都应该添加到 base_score
参数中;但是,如果 CatBoost
中有类似的参数,我就找不到了。 (如果参数在 CatBoost
中使用不同的名称,我不知道它叫什么。)此外,CatBoost
树中的值不仅仅与原始数据集有一些常量的不同;最大和最小叶节点之间的差异约为7,而原始数据集中size
的最大值和最小值之间的差异约为15.
我查看了 CatBoost
文档但没有成功。 “Model values”部分表示回归值是“应用模型产生的数字”,这对我来说表明它们应该在原始数据集的范围内。 (predict()
的输出也是如此,所以我不清楚这部分是否适用于绘制的决策树。)
搜索此函数get_scale_and_bias
Return 模型的规模和偏差。
这些值会影响应用模型的结果,因为模型预测结果的计算方式如下:
\sum leaf_values \cdot scale + bias∑leaf_values⋅scale+bias
问题中例子的应用
这里是适用于同一数据集的稍微不同的模型(使用与上述相同的代码)。
要将叶值转换为原始数据比例,请使用 get_scale_and_bias()
返回的比例和偏差。我使用 _get_tree_leaf_values()
提取了叶子;此函数 returns 表示叶子的字符串,因此我们必须进行一些正则表达式解析以获取实际值。我还 hand-coded 每个叶子的期望值,基于上面的 data-generating 过程。
# Get the scale and bias from the model.
sb = m.get_scale_and_bias()
# Apply the scale and bias to the leaves of the tree; compare to expected
# values for each leaf.
import re
[{'expected': [15, 25, 25, None, 20, 30, 30, None][i],
'actual': (float(re.sub(r'^val = (-?[0-9]+([.][0-9]+)?).*$', '\1', leaf))
* sb[0]) + sb[1]}
for i, leaf in enumerate(m._get_tree_leaf_values(0))]
我们看到预测值并不完美,但至少在正确的范围内。
[{'expected': 15, 'actual': 19.210155044555663},
{'expected': 25, 'actual': 24.067155044555665},
{'expected': 25, 'actual': 24.096155044555665},
{'expected': None, 'actual': 22.624155044555664},
{'expected': 20, 'actual': 21.309155044555663},
{'expected': 30, 'actual': 26.244155044555665},
{'expected': 30, 'actual': 26.249155044555664},
{'expected': None, 'actual': 22.624155044555664}]
谜题
我无法解释 CatBoostRegressor
树的叶子中的值。拟合模型正确地捕获了数据集的逻辑,但是当我绘制树图时值的比例与实际数据集的比例不匹配。
在此示例中,我们预测 size
,其值约为 15-30,具体取决于观察的 color
和 age
。
import random
import pandas as pd
import numpy as np
from catboost import Pool, CatBoostRegressor
# Create a fake dataset.
n = 1000
random.seed(1)
df = pd.DataFrame([[random.choice(['red', 'blue', 'green', 'yellow']),
random.random() * 100]
for i in range(n)],
columns=['color', 'age'])
df['size'] = np.select([np.logical_and(np.logical_or(df.color == 'red',
df.color == 'blue'),
df.age < 50),
np.logical_or(df.color == 'red',
df.color == 'blue'),
df.age < 50,
True],
[np.random.normal(loc=15, size=n),
np.random.normal(loc=20, size=n),
np.random.normal(loc=25, size=n),
np.random.normal(loc=30, size=n)])
# Fit a CatBoost regressor to the dataset.
pool = Pool(df[['color', 'age']], df['size'],
feature_names=['color', 'age'], cat_features=[0])
m = CatBoostRegressor(n_estimators=10, max_depth=3, one_hot_max_size=4,
random_seed=1)
m.fit(pool)
# Visualize the first regression tree (saves to a pdf). Values in leaf nodes
# are not on the scale of the original dataset.
m.plot_tree(tree_idx=0, pool=pool).render('regression_tree')
模型在 age
上以正确的值(大约 50)拆分,并且它正确地了解到红色和蓝色观察值不同于绿色和黄色观察值。叶子中的值排序正确(例如,red/blue 50 以下的观测值最小),但比例完全不同。
predict()
函数 returns 原始数据集规模上的值。
>>> df['predicted'] = m.predict(df)
>>> df.sample(n=10)
color age size predicted
676 yellow 66.305095 30.113389 30.065519
918 yellow 55.209821 29.944622 29.464825
705 yellow 1.742565 24.209283 24.913988
268 blue 76.749979 20.513211 20.019020
416 blue 59.807800 18.807197 19.949336
326 red 4.621795 14.748898 14.937314
609 yellow 99.165027 28.942243 29.823422
421 green 40.731038 26.078450 24.846742
363 yellow 2.461971 25.506517 24.913988
664 red 5.206448 16.579706 14.937314
我试过的
我想知道是否正在进行某种简单的规范化,但事实显然并非如此。例如,年龄 < 50 的红色观察值在树中被指定为 -3.418,这与真实值的 z 分数(大约 15)相去甚远。
>>> (15 - np.mean(df['size'])) / np.std(df['size'])
-1.3476124913754326
base_score
参数中;但是,如果 CatBoost
中有类似的参数,我就找不到了。 (如果参数在 CatBoost
中使用不同的名称,我不知道它叫什么。)此外,CatBoost
树中的值不仅仅与原始数据集有一些常量的不同;最大和最小叶节点之间的差异约为7,而原始数据集中size
的最大值和最小值之间的差异约为15.
我查看了 CatBoost
文档但没有成功。 “Model values”部分表示回归值是“应用模型产生的数字”,这对我来说表明它们应该在原始数据集的范围内。 (predict()
的输出也是如此,所以我不清楚这部分是否适用于绘制的决策树。)
搜索此函数get_scale_and_bias Return 模型的规模和偏差。
这些值会影响应用模型的结果,因为模型预测结果的计算方式如下: \sum leaf_values \cdot scale + bias∑leaf_values⋅scale+bias
问题中例子的应用
这里是适用于同一数据集的稍微不同的模型(使用与上述相同的代码)。
要将叶值转换为原始数据比例,请使用 get_scale_and_bias()
返回的比例和偏差。我使用 _get_tree_leaf_values()
提取了叶子;此函数 returns 表示叶子的字符串,因此我们必须进行一些正则表达式解析以获取实际值。我还 hand-coded 每个叶子的期望值,基于上面的 data-generating 过程。
# Get the scale and bias from the model.
sb = m.get_scale_and_bias()
# Apply the scale and bias to the leaves of the tree; compare to expected
# values for each leaf.
import re
[{'expected': [15, 25, 25, None, 20, 30, 30, None][i],
'actual': (float(re.sub(r'^val = (-?[0-9]+([.][0-9]+)?).*$', '\1', leaf))
* sb[0]) + sb[1]}
for i, leaf in enumerate(m._get_tree_leaf_values(0))]
我们看到预测值并不完美,但至少在正确的范围内。
[{'expected': 15, 'actual': 19.210155044555663},
{'expected': 25, 'actual': 24.067155044555665},
{'expected': 25, 'actual': 24.096155044555665},
{'expected': None, 'actual': 22.624155044555664},
{'expected': 20, 'actual': 21.309155044555663},
{'expected': 30, 'actual': 26.244155044555665},
{'expected': 30, 'actual': 26.249155044555664},
{'expected': None, 'actual': 22.624155044555664}]