考虑以下简单的分类问题(Python,scikit-learn)
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
def get_product_data(size):
'''
Given a size(int), sets `log10(size)` features to be uniform
random variables `Xi` in [-1,1] and an target `y` given by 1 if
their product `P` is larger than 0.0 and zero otherwise.
Returns a pandas DataFrame.
'''
n_features = int(max(2, np.log10(size)))
features = dict(('x%d' % i, 2*np.random.rand(size) - 1) for i in range(n_features))
y = np.prod(list(features.values()), axis=0)
y = y > 0.0
features.update({'y': y.astype(int)})
return pd.DataFrame(features)
# create random data
df = get_product_data(1000)
X = np.array(df.drop(df.columns[-1], axis=1))
y = df['y']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33,
random_state=1)
def predict(clf):
'''
Splits train/test with a fixed seed, fits, and returns the accuracy
'''
clf.fit(X_train, y_train)
return accuracy_score(y_test, clf.predict(X_test))和下列分类器:
foo10 = RandomForestClassifier(10, max_features=None, bootstrap=False)
foo100 = RandomForestClassifier(100, max_features=None, bootstrap=False)
foo200 = RandomForestClassifier(200, max_features=None, bootstrap=False)为什么
predict(foo10) # 0.906060606061
predict(foo100) # 0.933333333333
predict(foo200) # 0.915151515152给出不同的分数?
具体来说,与
max_features=None,为每棵树选择所有特性。bootstrap=False,没有自举的样本max_depth=None (默认),所有树都达到最大深度我希望每棵树都是完全一样的。因此,不管森林有多少树,预测应该是相等的。在这个例子中,树的可变性从何而来?
我还需要在RandomForestClassifier.__init__中引入哪些进一步的参数,使foo*有相同的分数呢?
发布于 2017-02-07 11:39:33
真是有趣的谜题。
首先要做的是。DecisionTreeClassifier具有一定的随机性。例如,分离器码随机地遍历这些特性:
f_j = rand_int(n_drawn_constants, f_i - n_found_constants,
random_state)您的数据很小,来自相同的发行版。这意味着你将有很多相同的纯度分数,取决于迭代是如何完成的。如果你(a)增加你的数据,或者(b)让它更容易分离,你就会发现问题应该得到改善。
为了澄清:如果算法计算特征A的分数,然后计算特征B的分数并得到N,或者如果它首先计算特征B的分数,然后计算特征A的分数,然后它得到相同的分数N,您可以看到每个决策树是如何不同的,并且在测试期间有不同的分数,即使训练测试是相同的(当然,如果是max_depth=None,则是100%)。(你可以证实这一点。)
在我探索您的问题期间,我用我自己实现的随机森林生成了以下代码。因为花了我一段时间,我想我还是把它贴在这里好了。)说真的,它可能是有用的。您可以尝试从我的实现中禁用random_state,以了解我的意思。
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
import numpy as np
class MyRandomForestClassifier:
def __init__(self, n_estimators):
self.n_estimators = n_estimators
def fit(self, X, y):
self.trees = [DecisionTreeClassifier(random_state=1).fit(X, y)
for _ in range(self.n_estimators)]
return self
def predict(self, X):
yp = [tree.predict(X) for tree in self.trees]
return ((np.sum(yp, 0) / len(self.trees)) > 0.5).astype(int)
def score(self, X, y):
return accuracy_score(y, self.predict(X))
for alpha in (1, 0.1, 0.01):
np.random.seed(1)
print('# alpha: %s' % str(alpha))
N = 1000
X = np.random.random((N, 10))
y = np.r_[np.zeros(N//2, int), np.ones(N//2, int)]
X[y == 1] = X[y == 1]*alpha
Xtr, Xts, ytr, yts = train_test_split(X, y)
print('## sklearn forest')
for n_estimators in (1, 10, 100, 200, 500):
m = RandomForestClassifier(
n_estimators, max_features=None, bootstrap=False)
m.fit(Xtr, ytr)
print('%3d: %.4f' % (n_estimators, m.score(Xts, yts)))
print('## my forest')
for n_estimators in (1, 10, 100, 200, 500):
m = MyRandomForestClassifier(n_estimators)
m.fit(Xtr, ytr)
print('%3d: %.4f' % (n_estimators, m.score(Xts, yts)))
print()摘要:每个DecisionTreeClassifier都是随机的,像您这样的数据很小,来自相同分布的数据必然会产生稍微不同的树,即使随机森林本身是确定性的。您可以通过向每个DecisionTreeClassifier传递相同的种子来解决这个问题,这可以使用random_state=something进行。RandomForestClassifier还有一个random_state参数,它沿着每个DecisionTreeClassifier传递这个参数。(这有点不正确,请参阅编辑。)
EDIT2:虽然这消除了训练中的随机性成分,但是决策树仍然是不同的。问题是,sklearn组合根据给出的随机状态为每个孩子生成一个新的随机种子。它们不传递相同的random_state。
您可以通过从集成基模块(特别是_set_random_states )中检查这条线方法来看到这种情况,后者将random_state传播到组件的子模块中。
发布于 2017-02-07 12:54:00
捡起里卡多·克鲁兹的答复:
原因是DecisionTreeClassifier不是确定性分类器。具体来说,当在导致度量相同减少的两个特性之间分裂时,DecisionTreeClassifier会随机选择一个。问题中所观察到的波动是由这一点引起的。
这一观察的推论是,scikit-learn的随机森林将引导用于3种不同的事情:
冻结items (使用bootstrap=False)和features (使用max_depth=None)不足以冻结splitting。冻结splitting的唯一方法是使用固定的random_state。
请注意,仅使用相同的random_state并不足以冻结一切,即
foo10 = RandomForestClassifier(10, random_state=1)
foo100 = RandomForestClassifier(100, random_state=1)
foo200 = RandomForestClassifier(200, random_state=1)不要给同样的分数。
因此,确保分类器为任何n_estimators提供相同结果的唯一方法是将其初始化为
RandomForestClassifier(n_estimators, max_features=None, bootstrap=False, random_state=1)这对分类本身并不特别有帮助,但可以更好地理解引擎盖下正在进行的工作。
https://datascience.stackexchange.com/questions/16800
复制相似问题