scikit-learn-contrib / sklearn-pandas

Pandas integration with sklearn
Other
2.81k stars 412 forks source link

The 'penalty' parameter of LogisticRegression must be a str among {'l1', 'l2', 'elasticnet'} or None. Got 'none' instead. #265

Open liuyameng128 opened 7 months ago

liuyameng128 commented 7 months ago

`%matplotlib widget import matplotlib.pyplot as plt from ipywidgets import Output from plt_overfit import overfit_example, output plt.style.use('./deeplearning.mplstyle')

plt.close("all") display(output) ofit = overfit_example(False)`

error message: `InvalidParameterError Traceback (most recent call last) File D:\Python\Lib\site-packages\ipywidgets\widgets\widget_output.py:103, in Output.capture..capture_decorator..inner(*args, kwargs) 101 self.clear_output(*clear_args, *clear_kwargs) 102 with self: --> 103 return func(args, kwargs)

File D:\ppt\jupyter数据处理\week3\Optional Labs\plt_overfit.py:323, in overfit_example.fitdata_clicked(self, event) 320 @output.capture() # debug 321 def fitdata_clicked(self,event): 322 if self.logistic: --> 323 self.logistic_regression() 324 else: 325 self.linear_regression()

File D:\ppt\jupyter数据处理\week3\Optional Labs\plt_overfit.py:365, in overfit_example.logisticregression(self) 362 C = 1/self.lambda 363 lr = LogisticRegression(C=C, max_iter=10000) --> 365 lr.fit(self.X_mapped_scaled,self.y) 366 #print(lr.score(self.X_mappedscaled, self.y)) 367 self.w = lr.coef.reshape(-1,)

File D:\Python\Lib\site-packages\sklearn\base.py:1467, in _fit_context..decorator..wrapper(estimator, *args, *kwargs) 1462 partial_fit_and_fitted = ( 1463 fit_method.name == "partial_fit" and _is_fitted(estimator) 1464 ) 1466 if not global_skip_validation and not partial_fit_and_fitted: -> 1467 estimator._validate_params() 1469 with config_context( 1470 skip_parameter_validation=( 1471 prefer_skip_nested_validation or global_skip_validation 1472 ) 1473 ): 1474 return fit_method(estimator, args, **kwargs)

File D:\Python\Lib\site-packages\sklearn\base.py:666, in BaseEstimator._validate_params(self) 658 def _validate_params(self): 659 """Validate types and values of constructor parameters 660 661 The expected type and values must be defined in the _parameter_constraints (...) 664 accepted constraints. 665 """ --> 666 validate_parameter_constraints( 667 self._parameter_constraints, 668 self.get_params(deep=False), 669 caller_name=self.class.name, 670 )

File D:\Python\Lib\site-packages\sklearn\utils_param_validation.py:95, in validate_parameter_constraints(parameter_constraints, params, caller_name) 89 else: 90 constraints_str = ( 91 f"{', '.join([str(c) for c in constraints[:-1]])} or" 92 f" {constraints[-1]}" 93 ) ---> 95 raise InvalidParameterError( 96 f"The {param_name!r} parameter of {caller_name} must be" 97 f" {constraints_str}. Got {param_val!r} instead." 98 )

InvalidParameterError: The 'penalty' parameter of LogisticRegression must be a str among {'l1', 'l2', 'elasticnet'} or None. Got 'none' instead.`

hu-minghao commented 7 months ago

你好,已收到,谢谢。

liuyameng128 commented 7 months ago

plt_overfit.py is shown below: `""" plot_overfit class and assocaited routines that plot an interactive example of overfitting and its solutions """ import math from ipywidgets import Output from matplotlib.gridspec import GridSpec from matplotlib.widgets import Button, CheckButtons from sklearn.linear_model import LogisticRegression, Ridge from lab_utils_common import np, plt, dlc, predict_logistic, plot_data, zscore_normalize_features

def map_one_feature(X1, degree): """ Feature mapping function to polynomial features """ X1 = np.atleast1d(X1) out = [] string = "" k = 0 for i in range(1, degree+1): out.append((X1**i)) string = string + f"w{{{k}}}{munge('x_0',i)} + " k += 1 string = string + ' b' #add b to text equation, not to data return np.stack(out, axis=1), string

def map_feature(X1, X2, degree): """ Feature mapping function to polynomial features """ X1 = np.atleast_1d(X1) X2 = np.atleast_1d(X2)

out = []
string = ""
k = 0
for i in range(1, degree+1):
    for j in range(i + 1):
        out.append((X1**(i-j) * (X2**j)))
        string = string + f"w_{{{k}}}{munge('x_0',i-j)}{munge('x_1',j)} + "
        k += 1
#print(string + 'b')
return np.stack(out, axis=1), string + ' b'

def munge(base, exp): if exp == 0: return '' if exp == 1: return base return base + f'^{{{exp}}}'

def plot_decision_boundary(ax, x0r,x1r, predict, w, b, scaler = False, mu=None, sigma=None, degree=None): """ Plots a decision boundary Args: x0r : (array_like Shape (1,1)) range (min, max) of x0 x1r : (array_like Shape (1,1)) range (min, max) of x1 predict : function to predict z values scalar : (boolean) scale data or not """

h = .01  # step size in the mesh
# create a mesh to plot in
xx, yy = np.meshgrid(np.arange(x0r[0], x0r[1], h),
                     np.arange(x1r[0], x1r[1], h))

# Plot the decision boundary. For that, we will assign a color to each
# point in the mesh [x_min, m_max]x[y_min, y_max].
points = np.c_[xx.ravel(), yy.ravel()]
Xm,_ = map_feature(points[:, 0], points[:, 1],degree)
if scaler:
    Xm = (Xm - mu)/sigma
Z = predict(Xm, w, b)

# Put the result into a color plot
Z = Z.reshape(xx.shape)
contour = ax.contour(xx, yy, Z, levels = [0.5], colors='g')
return contour

use this to test the above routine

def plot_decision_boundary_sklearn(x0r, x1r, predict, degree, scaler = False): """ Plots a decision boundary Args: x0r : (array_like Shape (1,1)) range (min, max) of x0 x1r : (array_like Shape (1,1)) range (min, max) of x1 degree: (int) degree of polynomial predict : function to predict z values scaler : not sure """

h = .01  # step size in the mesh
# create a mesh to plot in
xx, yy = np.meshgrid(np.arange(x0r[0], x0r[1], h),
                     np.arange(x1r[0], x1r[1], h))

# Plot the decision boundary. For that, we will assign a color to each
# point in the mesh [x_min, m_max]x[y_min, y_max].
points = np.c_[xx.ravel(), yy.ravel()]
Xm = map_feature(points[:, 0], points[:, 1],degree)
if scaler:
    Xm = scaler.transform(Xm)
Z = predict(Xm)

# Put the result into a color plot
Z = Z.reshape(xx.shape)
plt.contour(xx, yy, Z, colors='g')
#plot_data(X_train,y_train)

for debug, uncomment the #@output statments below for routines you want to get error output from

In the notebook that will call these routines, import output

from plt_overfit import overfit_example, output

then, in a cell where the error messages will be the output of..

display(output)

output = Output() # sends hidden error messages to display when using widgets

class button_manager: ''' Handles some missing features of matplotlib check buttons on init: creates button, links to button_click routine, calls call_on_click with active index and firsttime=True on click: maintains single button on state, calls call_on_click '''

@output.capture()  # debug
def __init__(self,fig, dim, labels, init, call_on_click):
    '''
    dim: (list)     [leftbottom_x,bottom_y,width,height]
    labels: (list)  for example ['1','2','3','4','5','6']
    init: (list)    for example [True, False, False, False, False, False]
    '''
    self.fig = fig
    self.ax = plt.axes(dim)  #lx,by,w,h
    self.init_state = init
    self.call_on_click = call_on_click
    self.button  = CheckButtons(self.ax,labels,init)
    self.button.on_clicked(self.button_click)
    self.status = self.button.get_status()
    self.call_on_click(self.status.index(True),firsttime=True)

@output.capture()  # debug
def reinit(self):
    self.status = self.init_state
    self.button.set_active(self.status.index(True))      #turn off old, will trigger update and set to status

@output.capture()  # debug
def button_click(self, event):
    ''' maintains one-on state. If on-button is clicked, will process correctly '''
    #new_status = self.button.get_status()
    #new = [self.status[i] ^ new_status[i] for i in range(len(self.status))]
    #newidx = new.index(True)
    self.button.eventson = False
    self.button.set_active(self.status.index(True))  #turn off old or reenable if same
    self.button.eventson = True
    self.status = self.button.get_status()
    self.call_on_click(self.status.index(True))

class overfit_example(): """ plot overfit example """

pylint: disable=too-many-instance-attributes

# pylint: disable=too-many-locals
# pylint: disable=missing-function-docstring
# pylint: disable=attribute-defined-outside-init
def __init__(self, regularize=False):
    self.regularize=regularize
    self.lambda_=0
    fig = plt.figure( figsize=(8,6))
    fig.canvas.toolbar_visible = False
    fig.canvas.header_visible = False
    fig.canvas.footer_visible = False
    fig.set_facecolor('#ffffff') #white
    gs  = GridSpec(5, 3, figure=fig)
    ax0 = fig.add_subplot(gs[0:3, :])
    ax1 = fig.add_subplot(gs[-2, :])
    ax2 = fig.add_subplot(gs[-1, :])
    ax1.set_axis_off()
    ax2.set_axis_off()
    self.ax = [ax0,ax1,ax2]
    self.fig = fig

    self.axfitdata = plt.axes([0.26,0.124,0.12,0.1 ])  #lx,by,w,h
    self.bfitdata  = Button(self.axfitdata , 'fit data', color=dlc['dlblue'])
    self.bfitdata.label.set_fontsize(12)
    self.bfitdata.on_clicked(self.fitdata_clicked)

    #clear data is a future enhancement
    #self.axclrdata = plt.axes([0.26,0.06,0.12,0.05 ])  #lx,by,w,h
    #self.bclrdata  = Button(self.axclrdata , 'clear data', color='white')
    #self.bclrdata.label.set_fontsize(12)
    #self.bclrdata.on_clicked(self.clrdata_clicked)

    self.cid = fig.canvas.mpl_connect('button_press_event', self.add_data)

    self.typebut = button_manager(fig, [0.4, 0.07,0.15,0.15], ["Regression", "Categorical"],
                                   [False,True], self.toggle_type)

    self.fig.text(0.1, 0.02+0.21, "Degree", fontsize=12)
    self.degrbut = button_manager(fig,[0.1,0.02,0.15,0.2 ], ['1','2','3','4','5','6'],
                                    [True, False, False, False, False, False], self.update_equation)
    if self.regularize:
        self.fig.text(0.6, 0.02+0.21, r"lambda($\lambda$)", fontsize=12)
        self.lambut = button_manager(fig,[0.6,0.02,0.15,0.2 ], ['0.0','0.2','0.4','0.6','0.8','1'],
                                    [True, False, False, False, False, False], self.updt_lambda)

    #self.regbut =  button_manager(fig, [0.8, 0.08,0.24,0.15], ["Regularize"],
    #                               [False], self.toggle_reg)
    #self.logistic_data()

def updt_lambda(self, idx, firsttime=False):
  # pylint: disable=unused-argument
    self.lambda_ = idx * 0.2

def toggle_type(self, idx, firsttime=False):
    self.logistic = idx==1
    self.ax[0].clear()
    if self.logistic:
        self.logistic_data()
    else:
        self.linear_data()
    if not firsttime:
        self.degrbut.reinit()

@output.capture()  # debug
def logistic_data(self,redraw=False):
    if not redraw:
        m = 50
        n = 2
        np.random.seed(2)
        X_train = 2*(np.random.rand(m,n)-[0.5,0.5])
        y_train = X_train[:,1]+0.5  > X_train[:,0]**2 + 0.5*np.random.rand(m) #quadratic + random
        y_train = y_train + 0  #convert from boolean to integer
        self.X = X_train
        self.y = y_train
        self.x_ideal = np.sort(X_train[:,0])
        self.y_ideal =  self.x_ideal**2

    self.ax[0].plot(self.x_ideal, self.y_ideal, "--", color = "orangered", label="ideal", lw=1)
    plot_data(self.X, self.y, self.ax[0], s=10, loc='lower right')
    self.ax[0].set_title("OverFitting Example: Categorical data set with noise")
    self.ax[0].text(0.5,0.93, "Click on plot to add data. Hold [Shift] for blue(y=0) data.",
                    fontsize=12, ha='center',transform=self.ax[0].transAxes, color=dlc["dlblue"])
    self.ax[0].set_xlabel(r"$x_0$")
    self.ax[0].set_ylabel(r"$x_1$")

def linear_data(self,redraw=False):
    if not redraw:
        m = 30
        c = 0
        x_train = np.arange(0,m,1)
        np.random.seed(1)
        y_ideal = x_train**2 + c
        y_train = y_ideal + 0.7 * y_ideal*(np.random.sample((m,))-0.5)
        self.x_ideal = x_train #for redraw when new data included in X
        self.X = x_train
        self.y = y_train
        self.y_ideal = y_ideal
    else:
        self.ax[0].set_xlim(self.xlim)
        self.ax[0].set_ylim(self.ylim)

    self.ax[0].scatter(self.X,self.y, label="y")
    self.ax[0].plot(self.x_ideal, self.y_ideal, "--", color = "orangered", label="y_ideal", lw=1)
    self.ax[0].set_title("OverFitting Example: Regression Data Set (quadratic with noise)",fontsize = 14)
    self.ax[0].set_xlabel("x")
    self.ax[0].set_ylabel("y")
    self.ax0ledgend = self.ax[0].legend(loc='lower right')
    self.ax[0].text(0.5,0.93, "Click on plot to add data",
                    fontsize=12, ha='center',transform=self.ax[0].transAxes, color=dlc["dlblue"])
    if not redraw:
        self.xlim = self.ax[0].get_xlim()
        self.ylim = self.ax[0].get_ylim()

@output.capture()  # debug
def add_data(self, event):
    if self.logistic:
        self.add_data_logistic(event)
    else:
        self.add_data_linear(event)

@output.capture()  # debug
def add_data_logistic(self, event):
    if event.inaxes == self.ax[0]:
        x0_coord = event.xdata
        x1_coord = event.ydata

        if event.key is None:  #shift not pressed
            self.ax[0].scatter(x0_coord, x1_coord, marker='x', s=10, c = 'red', label="y=1")
            self.y = np.append(self.y,1)
        else:
            self.ax[0].scatter(x0_coord, x1_coord, marker='o', s=10, label="y=0", facecolors='none',
                               edgecolors=dlc['dlblue'],lw=3)
            self.y = np.append(self.y,0)
        self.X = np.append(self.X,np.array([[x0_coord, x1_coord]]),axis=0)
    self.fig.canvas.draw()

def add_data_linear(self, event):
    if event.inaxes == self.ax[0]:
        x_coord = event.xdata
        y_coord = event.ydata

        self.ax[0].scatter(x_coord, y_coord, marker='o', s=10, facecolors='none',
                               edgecolors=dlc['dlblue'],lw=3)
        self.y = np.append(self.y,y_coord)
        self.X = np.append(self.X,x_coord)
        self.fig.canvas.draw()

#@output.capture()  # debug
#def clrdata_clicked(self,event):
#    if self.logistic == True:
#        self.X = np.
#    else:
#        self.linear_regression()

@output.capture()  # debug
def fitdata_clicked(self,event):
    if self.logistic:
        self.logistic_regression()
    else:
        self.linear_regression()

def linear_regression(self):
    self.ax[0].clear()
    self.fig.canvas.draw()

    # create and fit the model using our mapped_X feature set.
    self.X_mapped, _ =  map_one_feature(self.X, self.degree)
    self.X_mapped_scaled, self.X_mu, self.X_sigma  = zscore_normalize_features(self.X_mapped)

    #linear_model = LinearRegression()
    #linear_model = Ridge(alpha=self.lambda_, normalize=True, max_iter=10000)
    linear_model = Ridge(alpha=self.lambda_, max_iter=10000)
    linear_model.fit(self.X_mapped_scaled, self.y )
    self.w = linear_model.coef_.reshape(-1,)
    self.b = linear_model.intercept_
    x = np.linspace(*self.xlim,30)  #plot line idependent of data which gets disordered
    xm, _ =  map_one_feature(x, self.degree)
    xms = (xm - self.X_mu)/ self.X_sigma
    y_pred = linear_model.predict(xms)

    #self.fig.canvas.draw()
    self.linear_data(redraw=True)
    self.ax0yfit = self.ax[0].plot(x, y_pred, color = "blue", label="y_fit")
    self.ax0ledgend = self.ax[0].legend(loc='lower right')
    self.fig.canvas.draw()

def logistic_regression(self):
    self.ax[0].clear()
    self.fig.canvas.draw()

    # create and fit the model using our mapped_X feature set.
    self.X_mapped, _ =  map_feature(self.X[:, 0], self.X[:, 1], self.degree)
    self.X_mapped_scaled, self.X_mu, self.X_sigma  = zscore_normalize_features(self.X_mapped)
    if not self.regularize or self.lambda_ == 0:
        lr = LogisticRegression(penalty='none', max_iter=10000)
    else:
        C = 1/self.lambda_
        lr = LogisticRegression(C=C, max_iter=10000)

    lr.fit(self.X_mapped_scaled,self.y)
    #print(lr.score(self.X_mapped_scaled, self.y))
    self.w = lr.coef_.reshape(-1,)
    self.b = lr.intercept_
    #print(self.w, self.b)
    self.logistic_data(redraw=True)
    self.contour = plot_decision_boundary(self.ax[0],[-1,1],[-1,1], predict_logistic, self.w, self.b,
                   scaler=True, mu=self.X_mu, sigma=self.X_sigma, degree=self.degree )
    self.fig.canvas.draw()

@output.capture()  # debug
def update_equation(self, idx, firsttime=False):
    #print(f"Update equation, index = {idx}, firsttime={firsttime}")
    self.degree = idx+1
    if firsttime:
        self.eqtext = []
    else:
        for artist in self.eqtext:
            #print(artist)
            artist.remove()
        self.eqtext = []
    if self.logistic:
        _, equation =  map_feature(self.X[:, 0], self.X[:, 1], self.degree)
        string = 'f_{wb} = sigmoid('
    else:
        _, equation =  map_one_feature(self.X, self.degree)
        string = 'f_{wb} = ('
    bz = 10
    seq = equation.split('+')
    blks = math.ceil(len(seq)/bz)
    for i in range(blks):
        if i == 0:
            string = string +  '+'.join(seq[bz*i:bz*i+bz])
        else:
            string = '+'.join(seq[bz*i:bz*i+bz])
        string = string + ')' if i == blks-1 else string + '+'
        ei = self.ax[1].text(0.01,(0.75-i*0.25), f"${string}$",fontsize=9,
                             transform = self.ax[1].transAxes, ma='left', va='top' )
        self.eqtext.append(ei)
    self.fig.canvas.draw()`
jatolentino commented 3 months ago

@hu-minghao @liuyameng128 According to this post sklearn LogisticRegression without regularization, on sklearn 0.21 and higher versions, the regularization can be disabled by passing the None value to penalty. Also, if you want to use a penalty pass 'l1' or 'l2'. So, please fix the lines 359 and 362 of the logistic_regression function of plt_overflit.py with penalty = None as follows:

def logistic_regression(self):
        self.ax[0].clear()
        self.fig.canvas.draw()

        # create and fit the model using our mapped_X feature set.
        self.X_mapped, _ =  map_feature(self.X[:, 0], self.X[:, 1], self.degree)
        self.X_mapped_scaled, self.X_mu, self.X_sigma  = zscore_normalize_features(self.X_mapped)
        if not self.regularize or self.lambda_ == 0:
            lr = LogisticRegression(penalty = None, max_iter = 10000)      #line fixed
        else:
            C = 1/self.lambda_
            lr = LogisticRegression(C = C, max_iter = 10000, penalty = None) #line fixed

        lr.fit(self.X_mapped_scaled, self.y)
        #print(lr.score(self.X_mapped_scaled, self.y))
        self.w = lr.coef_.reshape(-1, )
        self.b = lr.intercept_
        #print(self.w, self.b)
        self.logistic_data(redraw=True)
        self.contour = plot_decision_boundary(self.ax[0], [-1, 1], [-1, 1], predict_logistic, self.w, self.b,
                       scaler = True, mu = self.X_mu, sigma = self.X_sigma, degree = self.degree )
        self.fig.canvas.draw()