//  [python]
def reinit_from_data(self, data, var_types=None):
        """
        Reinitializing Gaussians' parameters to better
        cover the latent space
        Also resets TT cores

        Args:
            data: tensor of shape [num_objects, num_vars], data to
                reinitialize the Gaussians
            var_types:
        """
        new_tt_cores = []
        new_means = []
        new_log_stds = []

        components = []
        for i, var_descr in enumerate(self.distr_descr):
            cur_core = torch.randn(var_descr[1], self.tt_int, self.tt_int)
            cur_core = cur_core / (self.tt_int ** 2 * var_descr[1])
            new_tt_cores.append(nn.Parameter(cur_core))

            if torch.sum(torch.isnan(data[:, i])) == data.shape[0]:
                new_means.append(self.means[i])
                new_log_stds.append(self.log_stds[i])

                components.append(-1 * np.ones(data.shape[0]))
                continue

            if var_descr[0] == 'd':
                new_means.append(None)
                new_log_stds.append(None)
                cur_components = data[:, i].cpu().detach().numpy()
                cur_components[np.isnan(cur_components)] = -1

            elif var_descr[0] == 'c':
                gmm = GaussianMixture(n_components=var_descr[1])
                cur_data = data[:, i].cpu().detach().numpy()
                non_missings = np.logical_not(np.isnan(cur_data))

                cur_components = -1 * np.ones_like(cur_data)

                non_missed_data = cur_data[non_missings].reshape(-1, 1)
                gmm.fit(non_missed_data)
                cur_gmm_comp = gmm.predict(non_missed_data)
                cur_components[non_missings] = cur_gmm_comp

                cur_means = torch.from_numpy(gmm.means_[:, 0])
                cur_means = cur_means.float()
                cur_log_stds = torch.from_numpy(gmm.covariances_[:, 0, 0])
                cur_log_stds = torch.log(cur_log_stds.float() + self.eps) / 2

                new_means.append(nn.Parameter(cur_means))
                new_log_stds.append(nn.Parameter(cur_log_stds))

            components.append(cur_components.astype(np.int))

        if var_types is not None:
            usual_vars_idxs = [i for i in range(len(var_types)) if
                               var_types[i] == 0]
            target_vars_idxs = [i for i in range(len(var_types)) if
                                var_types[i] == 1]

            scores = np.zeros((len(target_vars_idxs), len(usual_vars_idxs)))

            for i in range(len(target_vars_idxs)):
                for j in range(len(usual_vars_idxs)):
                    tg_n = self.distr_descr[target_vars_idxs[i]][1]
                    us_n = self.distr_descr[usual_vars_idxs[j]][1]
                    mx = np.zeros((tg_n, us_n))

                    tg_comp = components[target_vars_idxs[i]]
                    us_comp = components[usual_vars_idxs[j]]
                    for x, y in zip(tg_comp, us_comp):
                        if x != -1 and y != -1:
                            mx[x, y] += 1

                    if mx.sum() == 0:
                        continue

                    mx += 1e-10

                    s = mx.sum(axis=0)
                    mx = mx / s[None, :]

                    scores[i, j] = -((np.log(mx) * mx).sum(
                        axis=0) * s).sum() / s.sum()

            groups = np.argmin(scores, axis=0)

            new_order = []

            for group_i in range(len(target_vars_idxs)):
                g_members = np.where(groups == group_i)[0]
                g_members = sorted(g_members, key=lambda s: scores[group_i, s])
                new_group = [target_vars_idxs[group_i]]

                for i, member in enumerate(g_members):
                    if i % 2 == 0:
                        new_group = new_group + [usual_vars_idxs[member]]
                    else:
                        new_group = [usual_vars_idxs[member]] + new_group

                new_order += new_group

            self.order = new_order

        for i in range(len(self.tt_cores)):
            self.tt_cores[i].data = new_tt_cores[i].data
            if new_means[i] is not None:
                self.means[i].data = new_means[i].data
                self.log_stds[i].data = new_log_stds[i].data