def make_splits(df,
                target,
                time_step=0,
                ntrain=0.8,
                nval=0.15,
                ntest=0.05):
    """
    Split the dataframe in train, validation and test dataframe.
    For models not autoregressive, it is necessary to modify the target variable to create lagged
    obersvations in order to predict the n future instants.
    These models will try to find dependent relationships between the target y(t+n) and the features x(t).

    Args:
        df: DataFrame
        target: Target variable.
        time_step: Number of lags.
        ntrain: Size for the training dataframe.
        nval: Size for the validation dataframe.
        ntest: Size for the test dataframe.

    Returns: Dict splited into training, validation and test dataframe. Also into features and target.
            {train:{X: , y: }, val:{X: , y: }, test:{X: , y: }}

    """
    # Target variable
    df = df.copy()
    y_target = df[target].shift(-int(time_step))
    target_t = f'{target}_(t+{time_step})'
    df[target_t] = y_target
    df = df.drop(columns=[target])
    # Keep only rows with non-NANs
    df = df[~df.isna().any(axis='columns')]

    # split into train, val, test datasets.
    n = len(df)
    train_df = df[0:int(n * ntrain)]
    val_df = df[int(n * ntrain):int(n * (ntrain + nval))]
    test_df = df[int(n * (1 - ntest)):]
    # split into features and target variables.
    x_train = train_df.drop(columns=target_t)
    x_val = val_df.drop(columns=target_t)
    x_test = test_df.drop(columns=target_t)
    y_train = train_df[target_t]
    y_val = val_df[target_t]
    y_test = test_df[target_t]

    splits_df = {'train': {}, 'val': {}, 'test': {}}
    splits_df['train']['X'] = x_train
    splits_df['train']['y'] = y_train
    splits_df['val']['X'] = x_val
    splits_df['val']['y'] = y_val
    splits_df['test']['X'] = x_test
    splits_df['test']['y'] = y_test

    return splits_df