Example #1
0
def main(args):
    if args.X_path[:-3] == 'csv':
        X = np.loadtxt(args.X_path, delimiter=',')
    # elif args.X_path[:-3] == 'xls':
    else:
        X = pandas.read_excel(args.X_path)
        X = np.array(X)
    W_est = notears.notears_linear_l1(X, lambda1=args.lambda1, loss_type=args.loss_type)
    assert utils.is_dag(W_est)
    np.savetxt(args.W_path, W_est, delimiter=',')
    plot_matrix.plot_matrix(args)
Example #2
0
            if h_new > 0.25 * h:
                rho *= 10
            else:
                break
        w_est, h = w_new, h_new
        alpha += rho * h
        if h <= h_tol or rho >= rho_max:
            break
    W_est = _adj(w_est)
    W_est[np.abs(W_est) < w_threshold] = 0
    return W_est


if __name__ == '__main__':
    import utils as ut
    ut.set_random_seed(1)

    n, d, s0, graph_type, sem_type = 100, 20, 20, 'ER', 'gauss'
    B_true = ut.simulate_dag(d, s0, graph_type)
    W_true = ut.simulate_parameter(B_true)
    np.savetxt('W_true.csv', W_true, delimiter=',')

    X = ut.simulate_linear_sem(W_true, n, sem_type)
    np.savetxt('X.csv', X, delimiter=',')

    W_est = notears_linear_l1(X, lambda1=0.1, loss_type='l2')
    assert ut.is_dag(W_est)
    np.savetxt('W_est.csv', W_est, delimiter=',')
    acc = ut.count_accuracy(B_true, W_est != 0)
    print(acc)
def main(args):
    starttime = datetime.datetime.now()
    torch.set_default_dtype(torch.double)
    np.set_printoptions(precision=3)

    # load data
    X_envs, X_test = utils.load_data(dataset_name=args.dataset_name,
                                     preprocess=args.preprocess,
                                     num_envs=args.num_envs)

    # set target variable Y
    y_index = args.y_index
    vertex_label = utils.load_vertex_label(dataset_name=args.dataset_name)
    # adjust dataset X according to y_index
    X_swap = []
    for X_env in X_envs:
        swap(X_env, 0, y_index)
        X_swap.append(X_env)
    X = np.stack(X_swap)
    # swap X_test
    swap(X_test, 0, y_index)
    #  we do not need swap label because when drawing, we keep the original order.

    # Build model
    n_envs, n, d = X.shape
    Y_pred_hidden = [args.Y_hidden] * (args.Y_hidden_layer - 1)
    notears_hidden = [args.hidden] * args.notears_hidden_layer
    model = isl.isl_module(n_envs=n_envs,
                           Y_dims=[d, args.hidden] + Y_pred_hidden + [1],
                           dims=[d] + notears_hidden + [1],
                           bias=True)
    if args.continue_path:
        pretrained_path = args.continue_path
        model.load_state_dict(torch.load(pretrained_path))
    model.to(device)

    # conduct Invariant Structure Learning (ISL)
    y_pred_loss, w_est_origin_envs = isl.notears_nonlinear(
        model,
        X,
        y_index=0,
        lambda1=args.lambda1,
        lambda2=args.lambda2,
        lambda1_Y=args.lambda1_Y,
        lambda2_Y_fc1=args.lambda2_Y_fc1,
        lambda2_Y_fc2=args.lambda2_Y_fc2,
        w_threshold=0,
        beta=args.beta)  # y_index always be 0, w-thresh always be zero

    # tune W for the best shd score
    g, w_true = utils.load_w_true(args.dataset_name)

    # save results
    os.makedirs(args.Output_path, exist_ok=True)
    for i in range(len(w_est_origin_envs)):  # for each environment
        swap_row_column(w_est_origin_envs[i], 0,
                        y_index)  # recover to original order
        if args.Only_Y_DAG:  # for boston housing, we only care Y related DAG
            w_est_origin_envs[i][:, 1:] = np.zeros(w_true[:, 1:].shape)
        # rank W
        wthresh_w_shd_dict = utils.rank_W(w_est_origin_envs[i],
                                          10,
                                          90,
                                          w_true,
                                          w_threshold_low=0,
                                          w_threshold_high=10,
                                          step_size=0.02)
        # select W
        w_est = None
        w_threshold = None
        for threshold, w_element in wthresh_w_shd_dict.items():
            if utils.is_dag(w_element[0]):
                w_est = w_element[0]
                w_threshold = threshold
                break
        exp = (args.Output_path + (
            'pretrain-IRM_BH_norm={}_wthreshold={}_beta={}_y_index={}_lam1' +
            '={}_lam2fc1={}_lam2fc2_laterY{}NO{}_Yhid={}').format(
                args.normalization, w_threshold, args.beta, args.y_index,
                args.lambda1_Y, args.lambda2_Y_fc1, args.lambda2_Y_fc2,
                args.Y_hidden_layer, args.notears_hidden_layer, args.Y_hidden))
        utils.save_dag(w_est, f'{exp}_{i}', vertex_label=vertex_label)
        np.savetxt(f'{exp}_West_env_{i}.csv', w_est, fmt='%.2f', delimiter=',')
        np.savetxt(f'{exp}_West_origin_env_{i}.csv',
                   w_est_origin_envs[i],
                   fmt='%.2f',
                   delimiter=',')

    # save accuracy
    acc = metrics.count_accuracy(w_true, w_est != 0)
    # acc = {}
    y = model.test(X_test)
    mse = squared_loss(y[:, 0], X_test[:, 0])
    acc['mse'] = mse
    print(acc)
    with open(f'{exp}_metrics.json', 'w+') as f:
        json.dump(acc, f)

    # save and load model weights
    model_save_path = exp + '_save_model.pt'
    torch.save(model.state_dict(), model_save_path)

    endtime = datetime.datetime.now()
    print('total time is ', (endtime - starttime).seconds)
Example #4
0
def main(args):
    torch.set_default_dtype(torch.double)
    np.set_printoptions(precision=3)

    # load data
    X = utils.load_data(dataset_name=args.dataset_name, num_envs=args.num_envs)

    # load vertex labels
    vertex_label = utils.load_vertex_label(dataset_name=args.dataset_name)

    # the initial potential causal parents for each variable
    if args.dataset_name == 'Insurance':
        Init_Relation = {
            'PropCost': ['ThisCarCost', 'OtherCarCost'],  # 0
            'GoodStudent': ['Age', 'SocioEcon'],  # 1
            'Age': ['GoodStudent', 'RiskAversion'],  # 2
            'SocioEcon': ['RiskAversion', 'MakeModel', 'HomeBase'],  # 3
            'RiskAversion':
            ['SocioEcon', 'DrivQuality', 'DrivingSkill', 'HomeBase'],  # 4
            'VehicleYear':
            ['SocioEcon', 'MakeModel', 'Antilock', 'CarValue', 'Airbag'],  # 5
            'ThisCarDam': ['RuggedAuto', 'Accident', 'ThisCarCost'],  # 6
            'RuggedAuto':
            ['VehicleYear', 'MakeModel', 'Antilock', 'Cushioning'],  # 7
            'Accident': ['ThisCarDam', 'RuggedAuto'],  # 8
            'MakeModel':
            ['SocioEcon', 'VehicleYear', 'RuggedAuto', 'CarValue'],  # 9
            'DrivQuality': ['RiskAversion', 'DrivingSkill'],  # 10
            'Mileage': ['MakeModel', 'CarValue'],  # 11
            'Antilock': ['VehicleYear', 'MakeModel'],  # 12
            'DrivingSkill': ['Age', 'DrivQuality'],  # 13
            'SeniorTrain': ['Age', 'RiskAversion'],  # 14
            'ThisCarCost': ['RuggedAuto', 'CarValue'],  # 15
            'Theft':
            ['ThisCarDam', 'MakeModel', 'CarValue', 'HomeBase',
             'AntiTheft'],  # 16
            'CarValue': ['VehicleYear', 'MakeModel'],  # 17
            'HomeBase': ['SocioEcon', 'RiskAversion'],  # 18
            'AntiTheft': ['SocioEcon', 'RiskAversion'],  # 19
            'OtherCarCost': ['RuggedAuto', 'Accident'],  # 20
            'OtherCar': ['SocioEcon'],  # 21
            'MedCost': ['Age', 'Accident', 'Cushioning'],  # 22
            'Cushioning': ['RuggedAuto', 'Airbag'],  # 23
            'Airbag': ['VehicleYear'],  # 24
            'ILiCost': ['Accident'],  # 25
            'DrivHist': ['RiskAversion', 'DrivingSkill'],  # 26
        }
    elif args.dataset_name == 'Sachs':
        Init_Relation = {
            'Raf': ['Mek'],
            'Mek': ['Raf'],
            'Plcg': ['PIP2'],
            'PIP2': ['Plcg', 'PIP3'],
            'PIP3': ['Plcg', 'PIP2'],
            'Erk': ['Akt', 'Mek', 'PKA'],
            'Akt': ['PKA', 'Erk'],
            'PKA': ['Akt'],
            'PKC': ['P38'],
            'P38': ['PKA', 'PKC'],
            'Jnk': ['PKC'],
        }
    Init_DAG = np.zeros((len(vertex_label), len(vertex_label)))
    for x in vertex_label:
        x_index = vertex_label.index(x)
        for y in Init_Relation[x]:  # for each causal parent of x
            y_index = vertex_label.index(y)
            Init_DAG[y_index, x_index] = 1

    n, d = X.shape
    model = isl.notearsmlp_self_supervised(dims=[d, args.hidden, 1],
                                           bias=True,
                                           Init_DAG=Init_DAG)
    model.to(device)

    # To use a different feature as label, change y_index to column index of the
    # feature.
    w_est_origin = isl.notears_nonlinear(model,
                                         X,
                                         lambda1=args.lambda1,
                                         lambda2=args.lambda2,
                                         w_threshold=0)  # keep origin w_est

    # tune W for the best shd score
    g, w_true = utils.load_w_true(args.dataset_name)

    wthresh_w_shd_dict = utils.rank_W(w_est_origin,
                                      10,
                                      90,
                                      w_true,
                                      w_threshold_low=0,
                                      w_threshold_high=10,
                                      step_size=0.01)
    w_est = None
    w_threshold = None
    for threshold, w_element in wthresh_w_shd_dict.items():
        if utils.is_dag(w_element[0]):
            w_est = w_element[0]
            w_threshold = threshold
            break

    exp = (args.Output_path +
           'notear_mlp_sachs_norm={}wthreshold={}lambda1={}lambda2={}'.format(
               args.normalization, w_threshold, args.lambda1, args.lambda2))

    os.makedirs(args.Output_path, exist_ok=True)

    np.savetxt(exp + '_w_est_origin.csv', w_est_origin, delimiter=',')
    np.savetxt(exp + '_w_est.csv', w_est, delimiter=',')
    utils.save_dag(w_est, exp + '_w_est', vertex_label=vertex_label)

    acc = metrics.count_accuracy(w_true, w_est != 0)
    print(acc)

    y = model(torch.from_numpy(X))
    y = y.cpu().detach().numpy()
    mse = squared_loss(y[:, 0], X[:, 0])
    print('mse:', mse)
    acc['mse'] = mse

    with open(f'{exp}_metrics.json', 'w+') as f:
        json.dump(acc, f)
def train(X, b_true, vertex_label, model_type, args):
    """Trains the model."""

    n_envs, n, d = X.shape
    os.makedirs(args.Output_path, exist_ok=True)
    if model_type == 'notear-mlp':
        X = np.vstack(X)
        model = nonlinear.NotearsMLP(dims=[d, args.hidden, 1], bias=True)
        w_est_origin = nonlinear.notears_nonlinear(model,
                                                   X,
                                                   lambda1=args.lambda1,
                                                   lambda2=args.lambda2,
                                                   w_threshold=0)

        wthresh_w_shd_dict = utils.rank_W(w_est_origin,
                                          2,
                                          10,
                                          b_true,
                                          w_threshold_low=0,
                                          w_threshold_high=5,
                                          step_size=0.02)
        w_est = None
        w_threshold = None
        for threshold, w_element in wthresh_w_shd_dict.items():
            if utils.is_dag(w_element[0]):
                w_est = w_element[0]
                w_threshold = threshold
                break

        exp = f'notear_mlp_syn_{args.synthetic_source}_W-thresh{round(w_threshold, 3)}'

        # save the learned W matrix
        np.savetxt(args.Output_path + f'{exp}_West.csv',
                   w_est,
                   fmt='%.3f',
                   delimiter=',')
        np.savetxt(args.Output_path + f'{exp}_WOrigin.csv',
                   w_est_origin,
                   fmt='%.3f',
                   delimiter=',')

        # save the learned DAG
        utils.save_dag(w_est,
                       args.Output_path + f'{exp}_DAG',
                       vertex_label=vertex_label)

        # count the accuracy of Y
        b_true_Y = np.zeros_like(b_true)
        b_true_Y[:, 0] = b_true[:, 0]
        w_est_Y = np.zeros_like(w_est)
        w_est_Y[:, 0] = w_est[:, 0]
        acc = metrices.count_accuracy(b_true_Y, w_est_Y != 0)
        metrics[f'{exp}_train_acc'] = acc

        y = model(torch.from_numpy(X))
        y = y.cpu().detach().numpy()

        mse = mean_squared_loss(y.shape[0], y[:, 0], X[:, 0])
        print('mse:', mse)
        metrics[f'{model_type}_train_MSE'] = mse

    elif model_type == 'notear-castle':
        X = np.vstack(X)
        model = nonlinear_castle.NotearsMLP(dims=[d, args.hidden, 1],
                                            bias=True)

        # To use a different feature as label, change y_index to column
        # index of the feature.
        w_est_origin = nonlinear_castle.notears_nonlinear(
            model,
            X,
            lambda1=args.lambda1,
            lambda2=args.lambda2,
            w_threshold=args.w_threshold)
        wthresh_w_shd_dict = utils.rank_W(w_est_origin,
                                          2,
                                          10,
                                          b_true,
                                          w_threshold_low=0,
                                          w_threshold_high=5,
                                          step_size=0.02)
        w_est = None
        w_threshold = None
        for threshold, w_element in wthresh_w_shd_dict.items():
            if utils.is_dag(w_element[0]):
                w_est = w_element[0]
                w_threshold = threshold
                break

        exp = f'notear_castle_syn_{args.synthetic_source}_W-thresh-{round(w_threshold, 3)}'

        # save the learned W matrix
        np.savetxt(args.Output_path + f'{exp}_West.csv',
                   w_est,
                   fmt='%.2f',
                   delimiter=',')
        np.savetxt(args.Output_path + f'{exp}_WOrigin.csv',
                   w_est_origin,
                   fmt='%.3f',
                   delimiter=',')

        # save the learned DAG
        utils.save_dag(w_est,
                       args.Output_path + f'{exp}_DAG',
                       vertex_label=vertex_label)

        # estimate the accuracy of Y
        b_true_Y = np.zeros_like(b_true)
        b_true_Y[:, 0] = b_true[:, 0]
        w_est_Y = np.zeros_like(w_est)
        w_est_Y[:, 0] = w_est[:, 0]
        acc = metrices.count_accuracy(b_true_Y, w_est_Y != 0)
        metrics[f'{exp}_train_acc'] = acc

        y = model(torch.from_numpy(X))
        y = y.cpu().detach().numpy()

        mse = mean_squared_loss(y.shape[0], y[:, 0], X[:, 0])
        print('mse:', mse)
        metrics[f'{model_type}_train_MSE'] = mse

    elif model_type == 'ISL':
        model = isl.isl_module(n_envs=n_envs,
                               Y_dims=[d, args.hidden, 1],
                               dims=[d, args.hidden, 1],
                               bias=True)
        model.to(device)

        # To use a different feature as label, change y_index to column index of
        # the feature.
        _, w_est_origin_envs = isl.notears_nonlinear(
            model,
            X,
            y_index=0,
            lambda1=args.lambda1,
            lambda2=args.lambda2,
            lambda1_Y=args.lambda1_Y,
            lambda2_Y_fc1=args.lambda2_Y_fc1,
            lambda2_Y_fc2=args.lambda2_Y_fc2,
            beta=args.beta,
            w_threshold=0)

        for i in range(len(w_est_origin_envs)):

            wthresh_w_shd_dict = utils.rank_W(w_est_origin_envs[i],
                                              2,
                                              30,
                                              b_true,
                                              w_threshold_low=0,
                                              w_threshold_high=5,
                                              step_size=0.02)
            w_est = None
            w_threshold = None
            for threshold, w_element in wthresh_w_shd_dict.items():
                if utils.is_dag(w_element[0]):
                    w_est = w_element[0]
                    w_threshold = threshold
                    break

            exp = f'notear_ISL_syn_{args.synthetic_source}_W-thresh{round(w_threshold, 3)}'

            # save the leared W matrix
            np.savetxt(args.Output_path + f'{exp}_West_{i}.csv',
                       w_est,
                       fmt='%.3f',
                       delimiter=',')
            np.savetxt(args.Output_path + f'{exp}_WOrigin_env_{i}.csv',
                       w_est_origin_envs[i],
                       fmt='%.3f',
                       delimiter=',')

            # save the learned DAG
            utils.save_dag(w_est,
                           args.Output_path + f'{exp}_DAG_{i}',
                           vertex_label=vertex_label)

            # count the accuracy of Y
            b_true_Y = np.zeros_like(b_true)
            b_true_Y[:, 0] = b_true[:, 0]
            w_est_Y = np.zeros_like(w_est)
            w_est_Y[:, 0] = w_est[:, 0]
            acc = metrices.count_accuracy(b_true_Y, w_est_Y != 0)
            print(acc)
            metrics[f'{exp}_train_env_{i}_acc'] = acc
            y = model.test(X)

            mse = mean_squared_loss(y.shape[0] * y.shape[1], y,
                                    X[:, :, 0][:, :, np.newaxis])
            print('mse:', mse)
            metrics[f'{exp}_train_env_{i}_mse'] = mse

    else:
        ValueError('Invalid model type')

    return model, w_est
utils.set_random_seed(5)

n = 1000  # samples
n_i = 8  # data points (X) per sample
d = 8  # DAG vertices
s0 = 8  # DAG edges
e = 20  # epigenetic markers
k = 4  # archetypes

graph_type, sem_type = 'ER', 'gauss'

# Create network and epigenetic archetypes
W_k = np.ones((k, d, d))
e_k = np.ones((k, e))
# Ensure any combination of networks is DAG
while not utils.is_dag(np.sum(W_k, axis=0)):
    for j in range(k):
        B_true = utils.simulate_dag(d, s0, graph_type)
        W_true = utils.simulate_parameter(B_true)
        W_k[j] = W_true
        e_k[j] = utils.simulate_epigenome(e)
np.savez('outputs/archetypes.npz', W_k=W_k, e_k=e_k)

# Generate n samples from k archetypes
subtypes = np.zeros((n, k))
W_n = np.zeros((n, d, d))
e_n = np.zeros((n, e))
X_n = np.zeros((n, n_i, d))
for i in range(n):
    weights = np.random.uniform(0, 1, k)
    weights /= np.sum(weights)
Example #7
0
    lag_range = range(1, 12 + 1)
    all_variable_names = list(df.columns)
    plotname = "TemporalModel__" + file
    plotname_REDUCED = "TemporalModel*REDUCED*__" + file

    #lambda1 used in example provided by authors is 0.1
    #default w_threshold=0.3

    for lambda1 in [0.1]:
        for w_threshold in [0.3]:

            W_est = notears.notears_linear_l1(X.copy(),
                                              lambda1=lambda1,
                                              loss_type='l2',
                                              w_threshold=w_threshold)
            if not utils.is_dag(W_est):
                plotname_add = '!!!NODAG!!!'
            else:
                plotname_add = ''

            np.savetxt('AdjMatrix_' + plotname + '_lambda1=' + str(lambda1) +
                       '_Wthresh=' + str(w_threshold) + plotname_add + '.csv',
                       W_est,
                       delimiter=',')

            plot_graph.visualize_temporal(
                np.around(W_est, 2),
                feature_names=feature_names,
                full_feature_names=full_feature_names,
                lag_range=lag_range,
                all_variable_names=all_variable_names,
Example #8
0
def count_accuracy(B_true, B_est):
  """Computes various accuracy metrics for B_est.

    true positive = predicted association exists in condition in correct
    direction
    reverse = predicted association exists in condition in opposite direction
    false positive = predicted association does not exist in condition

  Args:
    B_true (np.ndarray): [d, d] ground truth graph, {0, 1}
    B_est (np.ndarray): [d, d] estimate, {0, 1, -1}, -1 is undirected edge in
      CPDAG.

  Returns:
    fdr: (reverse + false positive) / prediction positive
    tpr: (true positive) / condition positive
    fpr: (reverse + false positive) / condition negative
    shd: undirected extra + undirected missing + reverse
    nnz: prediction positive
  """
  if (B_est == -1).any():  # cpdag
    if not ((B_est == 0) | (B_est == 1) | (B_est == -1)).all():
      raise ValueError('B_est should take value in {0,1,-1}')
    if ((B_est == -1) & (B_est.T == -1)).any():
      raise ValueError('undirected edge should only appear once')
  else:  # dag
    if not ((B_est == 0) | (B_est == 1)).all():
      raise ValueError('B_est should take value in {0,1}')
    if not utils.is_dag(B_est):
      raise ValueError('B_est should be a DAG')
  d = B_true.shape[0]

  # linear index of nonzeros
  pred_und = np.flatnonzero(B_est == -1)
  pred = np.flatnonzero(B_est == 1)
  cond = np.flatnonzero(B_true)
  cond_reversed = np.flatnonzero(B_true.T)
  cond_skeleton = np.concatenate([cond, cond_reversed])

  # true pos
  true_pos = np.intersect1d(pred, cond, assume_unique=True)

  # treat undirected edge favorably
  true_pos_und = np.intersect1d(pred_und, cond_skeleton, assume_unique=True)
  true_pos = np.concatenate([true_pos, true_pos_und])

  # false pos
  false_pos = np.setdiff1d(pred, cond_skeleton, assume_unique=True)
  false_pos_und = np.setdiff1d(pred_und, cond_skeleton, assume_unique=True)
  false_pos = np.concatenate([false_pos, false_pos_und])

  # reverse
  extra = np.setdiff1d(pred, cond, assume_unique=True)
  reverse = np.intersect1d(extra, cond_reversed, assume_unique=True)

  # compute ratio
  pred_size = len(pred) + len(pred_und)
  cond_neg_size = 0.5 * d * (d - 1) - len(cond)
  fdr = float(len(reverse) + len(false_pos)) / max(pred_size, 1)
  tpr = float(len(true_pos)) / max(len(cond), 1)
  fpr = float(len(reverse) + len(false_pos)) / max(cond_neg_size, 1)

  # structural hamming distance
  pred_lower = np.flatnonzero(np.tril(B_est + B_est.T))
  cond_lower = np.flatnonzero(np.tril(B_true + B_true.T))
  extra_lower = np.setdiff1d(pred_lower, cond_lower, assume_unique=True)
  missing_lower = np.setdiff1d(cond_lower, pred_lower, assume_unique=True)
  shd = len(extra_lower) + len(missing_lower) + len(reverse)

  return {'fdr': fdr, 'tpr': tpr, 'fpr': fpr, 'shd': shd, 'nnz': pred_size}
Example #9
0
                rho *= 10
            else:
                break
        w_est, h = w_new, h_new
        alpha += rho * h
        if h <= h_tol or rho >= rho_max:
            break
    W_est = _adj(w_est)
    W_est[np.abs(W_est) < w_threshold] = 0
    return W_est


if __name__ == '__main__':
    import utils
    utils.set_random_seed(1)

    n, d, s0, graph_type, sem_type = 100, 20, 20, 'ER', 'gauss'
    B_true = utils.simulate_dag(d, s0, graph_type)
    W_true = utils.simulate_parameter(B_true)
    np.savetxt('W_true.csv', W_true, delimiter=',')

    X = utils.simulate_linear_sem(W_true, n, sem_type)
    np.savetxt('X.csv', X, delimiter=',')

    W_est = notears_linear(X, lambda1=0.1, loss_type='l2')
    assert utils.is_dag(W_est)
    np.savetxt('W_est.csv', W_est, delimiter=',')
    acc = utils.count_accuracy(B_true, W_est != 0)
    print(acc)