Reputation: 3607
I have the following class that works like this:
class DecisionTreeRegressor():
def __init__(self, min_leaf=5, impurity_threshold=1e-5,
root=None, leaf_value=None, impurity=None):
self.min_leaf = min_leaf
self.impurity_threshold = impurity_threshold
self.root = root
self._leaf_calculation = leaf_value
self._impurity_calculation = impurity
I would like to initiate the DecisionTreeRegressor
class within another class called RandomForestRegressor
, which currently has the following structure, for itself and its parent class RandomForest
:
class RandomForest():
def __init__(self, n_estimators=10, min_leaf=5,
sample_size = 2/3, min_impurity=1e-5):
self.n_estimators = n_estimators
self.min_leaf = min_leaf
self.sample_size = sample_size
self.min_impurity = min_impurity
class RandomForestRegressor(RandomForest):
def __init__(self):
super().__init__()
self.tree = DecisionTreeRegressor
self.trees = [self.tree(min_leaf=self.min_leaf)
for i in range(self.n_estimators)]
And this returns the following error message:
TypeError: __init__() got an unexpected keyword argument 'min_leaf'
I find this puzzling for the following reasons:
DecisionTreeRegressor(min_leaf=5)
Works just fine.
Also, if I change RandomForestRegressor
to:
class RandomForestRegressor(RandomForest):
def __init__(self):
super().__init__()
self.tree = DecisionTreeRegressor
self.trees = [self.tree() for i in range(self.n_estimators)]
This also works correctly, with self.trees
being a list filled with n different instances of the DecisionTreeRegressor
class.
Why is passing in the min_leaf
argument invoking an error message like it is?
Upvotes: 1
Views: 12114
Reputation: 216
A method or function, an instance of the method class, may define parameters. However, when the method is called, it can only take in the parameters it defined. For example:
def functionwithnoparameters():
pass
The code below will work.
functionwithnoparameters()
But, the code below will raise a TypeError because the function expected no parameters.
functionwithnoparameters(1)
It was given too many parameters, more than it expected so it raised TypeError. You were mistaken that only excess or too little value arguments can raise TypeError. But, excess or too little keyword arguments can also cause TypeError per this example.
functionwithnoparameters(one=1)
But, DecisionTreeRegressor didn't define any keyword parameters so it coughed up TypeError when one was given. That's the reason for the TypeError.
There are two solutions to your problem.
1) The interpreter thinks min_leaf and the other parameters are value parameters not keyword parameters. Because min_leaf is the first parameter, you can just use the value for min_leaf!
2) The cleaner solution. Parameters in Python default to be value parameters, and the end of the value parameters is marked when a parameter proceeded by a *, a tuple of all additional value arguments. If you want to mark the end of the value parameters without enabling unlimited value arguments, use * as a plain parameter. When the end of value parameters happens, keyword parameters begin. Unlimited keyword parameters occour if a parameter is proceeded by **. This must be the last of the method's parameters.
Now, to rewrite the DecisionTreeRegressor class according to the second solution:
class DecisionTreeRegressor():
def __init__(self, *, min_leaf=5, impurity_threshold=1e-5, root=None, leaf_value=None, impurity=None):
self.min_leaf = min_leaf
self.impurity_threshold = impurity_threshold
self.root = root
self._leaf_calculation = leaf_value
self._impurity_calculation = impurity
The little * before the keyword arguments completely solves the problem. The first solution is only a bandaid solution.
I feel dissatisfied with Jeff Mercado's answer because the TypeError occours because of lack of support rooted in the DecisionTreeRegressor class, not due to the lack of parameters in the RandomForestRegressor class' constructor.
However, I would highly reccommend that RandomForestRegressor's constructor should take in RandomForest's parameters and call RandomForest's constructor with those parameters, not with its default parameters. They can be value or keyword arguments, whatever you would like, now that I told you how to implement both.
Upvotes: 1
Reputation: 134891
I'm assuming you're calling this:
RandomForestRegressor(min_leaf=5)
The initializer for the RandomForestRegressor
class has no declared keyword arguments, it takes none at all.
You'll either need to explicitly add them in or add kwargs to the signature.
class RandomForestRegressor(RandomForest):
def __init__(self, **kwargs):
super().__init__(**kwargs)
Upvotes: 1