Ejemplo n.º 1
0
 def plot_path(self, result: dict, group_size: List[int] = None):
     """plot the solution path"""
     if group_size is None:
         group_size = self.group_size
     lams = list(result.keys())
     nz = compute_nonzeros(result[lams[-1]], group_size)[1]
     beta_norms = []
     for lam in lams:
         beta_norms.append(self.compute_group_norm(result[lam][1:], group_size))
     # lams = lams[1:]
     # beta_nonzero = []
     # for i in range(len(beta_norms)):
     #     beta_nonzero.append((np.array(beta_norms[i]) != 0).sum())
     # first_nonzero = beta_nonzero.index([i for i in beta_nonzero if i > 0][0])
     # if first_nonzero > 5:
     #     first_nonzero -= 5
     # else:
     #     first_nonzero = 0
     # lams = lams[first_nonzero:]
     # beta_norms = beta_norms[first_nonzero:]
     beta_norms = np.array(beta_norms)
     print(beta_norms.shape)
     plt.figure(figsize=(20, 5))
     plt.plot(lams, beta_norms[:, nz])
     plt.xlabel('Lambda')
     plt.ylabel('L2 norm of coefficients')
     plt.title('Group lasso path')
     plt.axis('tight')
     plt.legend(['beta' + str(i) for i in nz])
     plt.show()
Ejemplo n.º 2
0
 def fit_2(self,
           x: Union[np.ndarray, torch.Tensor],
           y: Union[np.ndarray, torch.Tensor],
           num_lams: int,
           max_iters: int = 1000,
           an: Union[int, float] = None,
           smooth: Union[float, int] = 0):
     """fit group lasso then followed by adaptive group lasso, saves time for basis expansion"""
     x = numpy_to_torch(x)
     y = numpy_to_torch(y)
     x = remove_intercept(x)
     x = self.normalize(x)
     x_basis = self.basis_expansion_(x, self.df, self.degree)
     group_size = [self.df] * x.shape[1]
     x_basis, group_size = add_intercept(x_basis, group_size)
     result = self.fit_path(x_basis,
                            y,
                            group_size,
                            num_lams,
                            max_iters,
                            smooth=smooth)
     beta_gl = result[min(list(result.keys()))]
     weights = self.compute_weights(beta_gl)
     result = self.fit_path(x_basis,
                            y,
                            group_size,
                            num_lams,
                            max_iters,
                            smooth=smooth,
                            weights=weights)
     best_gic = np.inf
     best_lam = 0
     best_beta = None
     if an is None:
         an = np.log(x.shape[1]) / x.shape[0]
     for lam in result.keys():
         beta_full = result[lam]
         gic = self.compute_gic(x_basis, y, beta_full, an, group_size)
         print(f"lam:{lam}, gic:{gic}")
         if gic < best_gic:
             best_lam = lam
             best_beta = beta_full
             best_gic = gic
     self.beta_agl_gic = best_beta
     self.beta = best_beta
     num_nz, nz = compute_nonzeros(best_beta, group_size)
     print(
         f"The best lam {best_lam} and the best gic {best_gic}. Finally selected {num_nz - 1} nonzeros: {nz}"
     )
     return self
Ejemplo n.º 3
0
 def plot_functions(self,
                    x: Union[np.ndarray, torch.Tensor],
                    cols: int = 5):
     """plot the estimated functions"""
     x = numpy_to_torch(x)
     x = remove_intercept(x)
     x_n = self.normalize_test(x)
     x_basis = self.basis_expansion_(x_n, self.df, self.degree)
     beta = self.beta[1:]
     nz, nzs = compute_nonzeros(beta, [self.df] * x.shape[1])
     nrows = nz // cols + 1
     fig, ax = plt.subplots(nrows=nrows, ncols=cols, figsize=(20, 12))
     x_o = torch.exp(x) - 0.1
     for i, j in enumerate(nzs):
         eta = torch.matmul(x_basis[:, self.df * j:self.df * (j + 1)],
                            beta[self.df * j:self.df * (j + 1)].double())
         ax.flatten()[i].scatter(x_o.detach().numpy()[:, j],
                                 eta.detach().numpy())
         ax.flatten()[i].title.set_text(f"Variable {j + 1}")
     plt.show()
Ejemplo n.º 4
0
 def solution_path(self, x: Union[np.ndarray, torch.Tensor], y: Union[np.ndarray, torch.Tensor],
                   num_lams: int, group_size: Union[int, List[int]], max_iters: int = 1000,
                   smooth: Union[float, int] = 0, recompute_hg: bool = True,
                   weight: List[Union[int, List[int]]] = None) \
         -> (List[torch.Tensor], List[float]):
     """
     fits the model with a use specified lambda
     :param x: the design matrix
     :param y: the response
     :param num_lams: number of lambdas
     :param group_size: list of group sizes, or simple group size if all groups are of the same size
     :param max_iters: the maximum number of iterations
     :param smooth: smoothness parameter
     :param recompute_hg: whether to recompute hg
     :param weight: feature weights
     :return: coefficients
     """
     x = numpy_to_torch(x)
     y = numpy_to_torch(y)
     self.group_size = group_size
     if isinstance(group_size, int):
         group_size = [1] + [group_size] * (x.shape[1] // group_size)
     if weight is None:
         weight = [0] + [1] * len(group_size)
     weights = [np.sqrt(group_size[i]) * weight[i] for i in range(len(group_size))]
     assert np.sum(group_size) == x.shape[1], "Sum of group sizes do not match number of variables."
     betas = []
     lam_max = self.find_max_lambda(x, y, weights[1:], group_size[1:])
     lam_max *= (1 + 1 / num_lams * 10)
     lams = list(np.linspace(0, lam_max, num_lams))
     lams.remove(0)
     lams.sort(reverse=True)
     lam_last = None
     for lam in lams:
         if not betas:
             # beta_full = self.solve(x, y, lam, group_size, max_iters, weights, smooth, recompute_hg)
             beta_full = torch.tensor([self.null_estimate(y)] + [0] * (sum(group_size) - 1))
             betas.append(beta_full)
             lam_last = lam
         else:
             beta = betas[-1]
             strong_index = self.strong_rule(x, y, beta, group_size, lam, lam_last, weights)
             x_s, group_size_s, weight_s = self.strong_x(x, group_size, strong_index, weights)
             # start = datetime.now().timestamp()
             beta_s = self.solve(x_s, y, lam, group_size_s, max_iters, weight_s, smooth, recompute_hg,
                                 weight_multiplied=True)
             # end = datetime.now().timestamp()
             # print(f"solve {end - start}")
             beta_full = self.strong_to_full_beta(beta_s, group_size, strong_index)
             v = self.fail_kkt(x, y, beta_full, group_size, lam, strong_index, weights)
             while len(v) > 0:
                 strong_index = list(set(strong_index + v))
                 x_s, group_size_s, weight_s = self.strong_x(x, group_size, strong_index, weights)
                 beta_s = self.solve(x_s, y, lam, group_size_s, max_iters, weight_s, smooth,
                                     recompute_hg, weight_multiplied=True)
                 beta_full = self.strong_to_full_beta(beta_s, group_size, strong_index)
                 v = self.fail_kkt(x, y, beta_full, group_size, lam, strong_index, weights)
             betas.append(beta_full)
             lam_last = lam
         num_nz, nz = compute_nonzeros(beta_full, group_size)
         print(f"Fitted lam = {lam}, {num_nz - 1} nonzero variables {nz}")
         if sum([group_size[i] for i in nz]) > 2 * x.shape[0]:
             lams = lams[:lams.index(lam) + 1]
             break
     return betas, lams,
Ejemplo n.º 5
0
 def compute_gic(self, x: torch.Tensor, y: torch.Tensor, beta: torch.Tensor,
                 an: Union[int, float], group_size: List[int]):
     """computes the generalized information criterion"""
     likelihood = self.compute_like(x, y, beta)
     num_nonzero = compute_nonzeros(beta, group_size)[0]
     return -2 * likelihood.detach().item() + an * num_nonzero