Python RandomizedSearchCV中类_权重的采样值

Python RandomizedSearchCV中类_权重的采样值,python,scikit-learn,hyperparameters,Python,Scikit Learn,Hyperparameters,我正在尝试使用RandomizedSearchCV在Scikit learn SVM分类器中使用类权重 clf= svm.SVC(probability=True, random_state=0) parameters = {'clf__C': scipy.stats.expon(scale=100), 'clf__gamma': scipy.stats.expon(scale=.1), 'clf__kernel': ['rbf'], 'clf__class_weight':['bala

我正在尝试使用
RandomizedSearchCV
在Scikit learn SVM分类器中使用类权重

clf= svm.SVC(probability=True, random_state=0)
parameters = {'clf__C': scipy.stats.expon(scale=100), 'clf__gamma': scipy.stats.expon(scale=.1),
    'clf__kernel': ['rbf'], 'clf__class_weight':['balanced', None]}
search=RandomizedSearchCV(estimator=clf, param_distributions=parameters, scoring='f1_micro',
                                       cv=5, n_iter=100, random_state=0)
search.fit(features,labels)
我有四节课。现在对于类_权重,我希望四个类中的每一个都有0到1之间的随机值。这可以用

'class_weight':[{0: w} for w in [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9]]
但这仅适用于一个类,并且值是离散的,不只是在0和1之间采样

我怎样才能解决这个问题

最后但并非最不重要的一点是,如果我使用的值介于0和1之间或介于1和10之间(即权重是否重新缩放),这是否重要


是否所有4类的权重总和总是相同的值(例如1)?

我不知道将分布作为字典键传递的可能性。作为对您提出的解决方案的改进,您可以使用:

from sklearn.utils.class_weight import compute_class_weight
from scipy.stats import lognorm

class_weight = compute_class_weight("balanced", np.unique(y), y)
class_weights = []
for mltp in lognorm(s = 1, loc = 1, scale = class_weight[0]).rvs(50):
    class_weights.append(dict(zip([0, 1], class_weight * [mltp, 1/mltp])))
然后,您可以将
class_权重
传递给
RandomizedSearchCV
clf_class_权重
参数中的
条目。将其扩展到多类场景或使用不同的发行版非常简单。
请注意,事实上,您已经进行了两次采样。一次来自真实分布,然后通过此样本的
随机搜索CV
。如果您确保在每次调用之前重新生成
class_权重
,或者确保初始样本足够大,那么这种解决方法在您的情况下应该可以很好地工作


编辑: 更好的解决方案是定义自己的类来实现
rvs
方法。即使不必将现有的
scipy.stats
distribution子类化为:

class ClassWeights(object):
    """
    Draw random variates for cases when parameter is a dict.
    Should be personalized as needed.
    """
    def __init__(self,y, *args, **kwargs):
        self.class_weights = compute_class_weight("balanced", np.unique(y), y)
        self._make_dists()

    def _make_dists(self):
        self.dist0 = gamma(self.class_weights[0])
        self.dist1 = gamma(self.class_weights[1])

    def rvs(self, *args, **kwargs):
        """override method for drawing random variates"""
        ret_val = { 0: self.dist0.rvs(*args, **kwargs),
                    1: self.dist1.rvs(*args, **kwargs)}
        return ret_val

在回答你的另外两个问题时:


权重可以取任何正值(包括0),它们的总和不必等于1。重要的是它们的相对大小,而不是绝对大小。

我不知道将分布作为字典键传递的可能性。作为对您提出的解决方案的改进,您可以使用:

from sklearn.utils.class_weight import compute_class_weight
from scipy.stats import lognorm

class_weight = compute_class_weight("balanced", np.unique(y), y)
class_weights = []
for mltp in lognorm(s = 1, loc = 1, scale = class_weight[0]).rvs(50):
    class_weights.append(dict(zip([0, 1], class_weight * [mltp, 1/mltp])))
然后,您可以将
class_权重
传递给
RandomizedSearchCV
clf_class_权重
参数中的
条目。将其扩展到多类场景或使用不同的发行版非常简单。
请注意,事实上,您已经进行了两次采样。一次来自真实分布,然后通过此样本的
随机搜索CV
。如果您确保在每次调用之前重新生成
class_权重
,或者确保初始样本足够大,那么这种解决方法在您的情况下应该可以很好地工作


编辑: 更好的解决方案是定义自己的类来实现
rvs
方法。即使不必将现有的
scipy.stats
distribution子类化为:

class ClassWeights(object):
    """
    Draw random variates for cases when parameter is a dict.
    Should be personalized as needed.
    """
    def __init__(self,y, *args, **kwargs):
        self.class_weights = compute_class_weight("balanced", np.unique(y), y)
        self._make_dists()

    def _make_dists(self):
        self.dist0 = gamma(self.class_weights[0])
        self.dist1 = gamma(self.class_weights[1])

    def rvs(self, *args, **kwargs):
        """override method for drawing random variates"""
        ret_val = { 0: self.dist0.rvs(*args, **kwargs),
                    1: self.dist1.rvs(*args, **kwargs)}
        return ret_val

在回答你的另外两个问题时:


权重可以取任何正值(包括0),它们的总和不必等于1。重要的是它们的相对大小,而不是绝对大小。

您可以尝试列表理解而不是长时间的解决方案。它在RandomForest中对我有效,我已经检查了RandomizedSearchCV

l1 = np.arange(0,1,0.01)
l2 = np.arange(0,1,0.01)
class_weight = [{0:i,1:j} for i,j in zip(l1,l2)]

您可以尝试列表理解而不是长的解决方案,它在RandomForest中对我有效,我已经检查了RandomizedSearchCV

l1 = np.arange(0,1,0.01)
l2 = np.arange(0,1,0.01)
class_weight = [{0:i,1:j} for i,j in zip(l1,l2)]

不,这些值可以是任意的,不能和1相加。@VivekKumar非常感谢。我可以问你是否还有其他问题的答案吗?你可以使用随机抽样来计算重量。但这需要在多次迭代中进行调整。例如,从[0,1]范围内的随机数开始。在下一次迭代中,选择与上一次迭代中选择的范围相近的范围。比如[0.45,0.65]。等等。看看随机抽样。不,这些值可以是任意的,总和不能等于1。@VivekKumar非常感谢。我可以问你是否还有其他问题的答案吗?你可以使用随机抽样来计算重量。但这需要在多次迭代中进行调整。例如,从[0,1]范围内的随机数开始。在下一次迭代中,选择与上一次迭代中选择的范围相近的范围。比如[0.45,0.65]。等等。看看随机抽样。