Beispiel #1
0
def test_calders():
    """Test calders."""
    data = DataTuple(
        x=pd.DataFrame(np.linspace(0, 1, 100), columns=["x"]),
        s=pd.DataFrame([1] * 75 + [0] * 25, columns=["s"]),
        y=pd.DataFrame([1] * 50 + [0] * 25 + [1] * 10 + [0] * 15,
                       columns=["y"]),
        name="TestData",
    )
    data, _ = em.train_test_split(data, train_percentage=1.0)
    assert len(em.query_dt(data, "s == 0 & y == 0")) == 15
    assert len(em.query_dt(data, "s == 0 & y == 1")) == 10
    assert len(em.query_dt(data, "s == 1 & y == 0")) == 25
    assert len(em.query_dt(data, "s == 1 & y == 1")) == 50
    assert em.query_dt(data,
                       "s == 1 & y == 0").x.min().min() == approx(0.50,
                                                                  abs=0.01)

    calders: PreAlgorithm = Calders(preferable_class=1, disadvantaged_group=0)
    new_train, new_test = calders.run(data, data.remove_y())

    pd.testing.assert_frame_equal(new_test.x, data.x)
    pd.testing.assert_frame_equal(new_test.s, data.s)

    assert len(em.query_dt(new_train, "s == 0 & y == 0")) == 10
    assert len(em.query_dt(new_train, "s == 0 & y == 1")) == 15
    assert len(em.query_dt(new_train, "s == 1 & y == 0")) == 30
    assert len(em.query_dt(new_train, "s == 1 & y == 1")) == 45

    assert len(data) == len(new_train)
    assert em.query_dt(new_train, "s == 1 & y == 1").x.min().min() == 0
    assert em.query_dt(new_train,
                       "s == 1 & y == 0").x.min().min() == approx(0.45,
                                                                  abs=0.01)
Beispiel #2
0
def test_apply_to_joined_df() -> None:
    """Tests apply_to_joined_df_function."""
    datatup = DataTuple(
        x=pd.DataFrame([3.0], columns=["a1"]),
        s=pd.DataFrame([4.0], columns=["b2"]),
        y=pd.DataFrame([6.0], columns=["c3"]),
        name=None,
    )

    def _identity(x: pd.DataFrame):
        return x

    result = datatup.apply_to_joined_df(_identity)
    pd.testing.assert_frame_equal(datatup.x, result.x)
    pd.testing.assert_frame_equal(datatup.s, result.s)
    pd.testing.assert_frame_equal(datatup.y, result.y)
Beispiel #3
0
def test_biased_split_sizes():
    """Test biased split sizes."""
    data = DataTuple(
        x=pd.DataFrame([0] * 1000, columns=["feat1-"]),
        s=pd.DataFrame([1] * 750 + [0] * 250, columns=["sens="]),
        y=pd.DataFrame([1] * 500 + [0] * 250 + [1] * 125 + [0] * 125,
                       columns=["label<"]),
        name="TestData",
    )

    biased1, subset = em.get_biased_subset(data,
                                           mixing_factor=0.0,
                                           unbiased_pcnt=0.8)
    assert len(biased1) < len(subset)
    biased1, subset = em.get_biased_subset(data,
                                           mixing_factor=0.0,
                                           unbiased_pcnt=0.2)
    assert len(biased1) > len(subset)

    biased2, debiased = em.get_biased_and_debiased_subsets(data,
                                                           mixing_factor=0.0,
                                                           unbiased_pcnt=0.8,
                                                           fixed_unbiased=True)
    assert len(biased2) < len(debiased)
    biased2, debiased = em.get_biased_and_debiased_subsets(data,
                                                           mixing_factor=0.0,
                                                           unbiased_pcnt=0.2,
                                                           fixed_unbiased=True)
    assert len(biased2) > len(debiased)
Beispiel #4
0
def test_concat():
    """Test concat."""
    x: pd.DataFrame = pd.DataFrame(columns=["a"], data=[[1]])
    s: pd.DataFrame = pd.DataFrame(columns=["b"], data=[[2]])
    y: pd.DataFrame = pd.DataFrame(columns=["c"], data=[[3]])
    data1 = DataTuple(x=x, s=s, y=y, name="test_data")
    x = pd.DataFrame(columns=["a"], data=[[4]])
    s = pd.DataFrame(columns=["b"], data=[[5]])
    y = pd.DataFrame(columns=["c"], data=[[6]])
    data2 = DataTuple(x=x, s=s, y=y, name="test_tuple")
    data3 = em.concat_dt([data1, data2], axis="index", ignore_index=True)
    pd.testing.assert_frame_equal(data3.x,
                                  pd.DataFrame(columns=["a"], data=[[1], [4]]))
    pd.testing.assert_frame_equal(data3.s,
                                  pd.DataFrame(columns=["b"], data=[[2], [5]]))
    pd.testing.assert_frame_equal(data3.y,
                                  pd.DataFrame(columns=["c"], data=[[3], [6]]))
Beispiel #5
0
def test_dataset_name_none() -> None:
    """Tests that a DataTuple can be saved without the name property."""
    datatup = DataTuple(
        x=pd.DataFrame([3.0], columns=["a1"]),
        s=pd.DataFrame([4.0], columns=["b2"]),
        y=pd.DataFrame([6.0], columns=["c3"]),
        name=None,
    )
    with TemporaryDirectory() as tmpdir:
        tmp_path = Path(tmpdir)
        path = tmp_path / "pytest.npz"
        datatup.to_npz(path)
        # reload from feather file
        reloaded = DataTuple.from_npz(path)
    assert reloaded.name is None
    pd.testing.assert_frame_equal(datatup.x, reloaded.x)
    pd.testing.assert_frame_equal(datatup.s, reloaded.s)
    pd.testing.assert_frame_equal(datatup.y, reloaded.y)
Beispiel #6
0
def test_data_tuple_len() -> None:
    """Test DataTuple len property."""
    datatup_unequal_len = DataTuple(
        x=pd.DataFrame([3.0, 2.0], columns=["a1"]),
        s=pd.DataFrame([4.0], columns=["b2"]),
        y=pd.DataFrame([6.0], columns=["c3"]),
        name=None,
    )
    with pytest.raises(AssertionError):
        len(datatup_unequal_len)

    datatup_equal_len = DataTuple(
        x=pd.DataFrame([3.0, 2.0, 1.0], columns=["a1"]),
        s=pd.DataFrame([4.0, 5.0, 9.0], columns=["b2"]),
        y=pd.DataFrame([6.0, 4.2, 6.7], columns=["c3"]),
        name=None,
    )
    assert len(datatup_equal_len) == 3
Beispiel #7
0
 def _run_script_command(self, train_path, test_path, pred_path):
     """Check if the dataframes loaded from the files are the same as the original ones."""
     del test_path
     loaded = DataTuple.from_npz(train_path)
     pd.testing.assert_frame_equal(data_tuple.x, loaded.x)
     pd.testing.assert_frame_equal(data_tuple.s, loaded.s)
     pd.testing.assert_frame_equal(data_tuple.y, loaded.y)
     # write a file for the predictions
     np.savez(pred_path, hard=np.load(train_path)["x"])
     return ["-c", "pass"]
Beispiel #8
0
def test_query():
    """Test query."""
    x: pd.DataFrame = pd.DataFrame(columns=["0a", "b"],
                                   data=[[0, 1], [2, 3], [4, 5]])
    s: pd.DataFrame = pd.DataFrame(columns=["c="], data=[[6], [7], [8]])
    y: pd.DataFrame = pd.DataFrame(columns=["d"], data=[[9], [10], [11]])
    data = DataTuple(x=x, s=s, y=y, name="test_data")
    selected = em.query_dt(data, "`0a` == 0 & `c=` == 6 & d == 9")
    pd.testing.assert_frame_equal(selected.x, x.head(1))
    pd.testing.assert_frame_equal(selected.s, s.head(1))
    pd.testing.assert_frame_equal(selected.y, y.head(1))
Beispiel #9
0
def simple_data() -> DataTuple:
    """Simple data for testing splitting methods."""
    # visual representation of the data:
    # s: ...111111111111111111111111111111111111111111111111111111111111110000000000000000000000000
    # y: ...111111111111111111111111111111111111110000000000000000000000001111111111000000000000000
    return DataTuple(
        x=pd.DataFrame([0] * 1000, columns=["x"]),
        s=pd.DataFrame([1] * 750 + [0] * 250, columns=["s"]),
        y=pd.DataFrame([1] * 500 + [0] * 250 + [1] * 100 + [0] * 150,
                       columns=["y"]),
        name="TestData",
    )
Beispiel #10
0
def test_issue_431():
    """This issue highlighted that error would be raised due to not all values existing in subsets of the data."""
    x = pd.DataFrame(np.random.randn(100), columns=["x"])
    s = pd.DataFrame(np.random.randn(100), columns=["s"])
    y = pd.DataFrame(np.random.randint(0, 5, 100), columns=["y"])
    data = DataTuple(x=x, s=s, y=y)
    train_test: Tuple[DataTuple, DataTuple] = train_test_split(data)
    train, test = train_test
    model: InAlgorithm = LR()
    predictions: Prediction = model.run(train, test)
    acc_per_sens = metric_per_sensitive_attribute(
        predictions, test, TPR(pos_class=1,
                               labels=list(range(y.nunique()[0]))))
    print(acc_per_sens)
Beispiel #11
0
def test_biased_split_nonbinary():
    """Test biased split nonbinary."""
    # generate data that uses -1 and 1 instead of 0 and 1 for s and y
    data = DataTuple(
        x=pd.DataFrame([0] * 1000, columns=["feat1-"]),
        s=pd.DataFrame([1] * 750 + [-1] * 250, columns=["sens="]),
        y=pd.DataFrame([1] * 500 + [-1] * 250 + [1] * 125 + [-1] * 125,
                       columns=["label<"]),
        name="TestData",
    )

    biased1, subset = em.get_biased_subset(data,
                                           mixing_factor=0.5,
                                           unbiased_pcnt=0.5)
    assert len(biased1) == approx(len(subset), abs=4)
Beispiel #12
0
def test_simple_saving() -> None:
    """Tests that a DataTuple can be saved."""
    data_tuple = DataTuple(
        x=pd.DataFrame({"a1": np.array([3.2, 9.4, np.nan, 0.0])}),
        s=pd.DataFrame({
            "b1": np.array([18, -3, int(1e10)]),
            "b2": np.array([1, 1, -1]),
            "b3": np.array([0, 1, 0]),
        }),
        y=pd.DataFrame({
            "c1": np.array([-2.0, -3.0, np.nan]),
            "c3": np.array([0.0, 1.0, 0.0])
        }),
        name="test data",
    )

    class CheckEquality(InAlgorithmAsync):
        """Dummy algorithm class for testing whether writing and reading feather files works."""
        def __init__(self) -> None:
            super().__init__(name="Check equality", seed=-1)

        def _run_script_command(self, train_path, test_path, pred_path):
            """Check if the dataframes loaded from the files are the same as the original ones."""
            del test_path
            loaded = DataTuple.from_npz(train_path)
            pd.testing.assert_frame_equal(data_tuple.x, loaded.x)
            pd.testing.assert_frame_equal(data_tuple.s, loaded.s)
            pd.testing.assert_frame_equal(data_tuple.y, loaded.y)
            # write a file for the predictions
            np.savez(pred_path, hard=np.load(train_path)["x"])
            return ["-c", "pass"]

        def _fit_script_command(self, train_path, model_path):
            """Check if the dataframes loaded from the files are the same as the original ones."""

        def _predict_script_command(self, model_path, test_path, pred_path):
            """Check if the dataframes loaded from the files are the same as the original ones."""

    data_x = CheckEquality().run(data_tuple, data_tuple)
    pd.testing.assert_series_equal(  # type: ignore[call-arg]
        data_tuple.x["a1"],
        data_x.hard,
        check_names=False)
Beispiel #13
0
def test_plot_no_tsne(toy_train_test: TrainTestPair):
    """Test plot."""
    train, _ = toy_train_test
    train = DataTuple(x=train.x[train.x.columns[:2]], s=train.s,
                      y=train.y)  # type: ignore[arg-type]
    save_2d_plot(train, "./plots/test.png")
Beispiel #14
0
def test_biased_split():
    """Test biased split."""
    data = DataTuple(
        x=pd.DataFrame([0] * 1000, columns=["feat1-"]),
        s=pd.DataFrame([1] * 750 + [0] * 250, columns=["sens="]),
        y=pd.DataFrame([1] * 500 + [0] * 250 + [1] * 125 + [0] * 125,
                       columns=["label<"]),
        name="TestData",
    )

    # =================================== mixing factor = 0 =======================================
    biased1, subset = em.get_biased_subset(data,
                                           mixing_factor=0.0,
                                           unbiased_pcnt=0.5)
    # expected behavior: in biased1, s=y everywhere; `subset` is just a subset of `data`

    assert biased1.s.shape == (313, 1)
    assert biased1.y.shape == (313, 1)
    assert (biased1.s.to_numpy() == biased1.y.to_numpy()).all()
    assert biased1.name == "TestData - Biased (tm=0.0)"

    # size is exactly 0.5 of the total
    assert subset.s.shape[0] == approx(
        500, abs=4)  # can be off by 4 because of proportional split
    assert subset.y.shape[0] == approx(500, abs=4)
    assert subset.name == "TestData - Subset (tm=0.0)"

    # the fraction of `data`points where y=s should be the same in the data and the subset
    subset_mean = (subset.s.to_numpy() == subset.y.to_numpy()).mean()
    data_mean = (data.s.to_numpy() == data.y.to_numpy()).mean()
    assert subset_mean == approx(data_mean, abs=0.01)

    biased2, debiased = em.get_biased_and_debiased_subsets(data,
                                                           mixing_factor=0.0,
                                                           unbiased_pcnt=0.5,
                                                           fixed_unbiased=True)
    # expected behavior: in biased2, s=y everywhere; in debiased, 50% s=y and 50% s!=y

    assert biased2.s.shape == (313, 1)
    assert biased2.y.shape == (313, 1)
    assert (biased2.s.to_numpy() == biased2.y.to_numpy()).all()

    assert debiased.s.shape == (374, 1)
    assert debiased.y.shape == (374, 1)
    # for the debiased subset, s=y half of the time
    count = np.count_nonzero(debiased.s.to_numpy() == debiased.y.to_numpy())
    assert count == 374 // 2

    # ================================= mixing factor = 0.5 =======================================
    biased1, subset = em.get_biased_subset(data,
                                           mixing_factor=0.5,
                                           unbiased_pcnt=0.5)
    # expected behavior: biased1 and `subset` are both just subsets of `data`

    assert biased1.s.shape[0] == approx(500, abs=4)
    assert biased1.y.shape[0] == approx(500, abs=4)
    data_mean = (data.s.to_numpy() == data.y.to_numpy()).mean()
    biased1_mean = (biased1.s.to_numpy() == biased1.y.to_numpy()).mean()
    assert biased1_mean == approx(data_mean, abs=0.01)

    assert subset.s.shape[0] == approx(500, abs=4)
    assert subset.y.shape[0] == approx(500, abs=4)

    # the fraction of `data`points where y=s should be the same in the data and the subset
    subset_mean = (subset.s.to_numpy() == subset.y.to_numpy()).mean()
    assert subset_mean == approx(data_mean, abs=0.01)

    biased2, debiased = em.get_biased_and_debiased_subsets(data,
                                                           mixing_factor=0.5,
                                                           unbiased_pcnt=0.5,
                                                           fixed_unbiased=True)
    # expected behavior: biased2 is just a subset of `data`; in debiased, 50% s=y and 50% s!=y

    assert biased2.s.shape[0] == approx(500, abs=4)
    assert biased2.y.shape[0] == approx(500, abs=4)
    data_mean = (data.s.to_numpy() == data.y.to_numpy()).mean()
    biased2_mean = (biased2.s.to_numpy() == biased2.y.to_numpy()).mean()
    assert biased2_mean == approx(data_mean, abs=0.01)

    assert debiased.s.shape == (374, 1)
    assert debiased.y.shape == (374, 1)
    # for the debiased subset, s=y half of the time
    count = np.count_nonzero(debiased.s.to_numpy() == debiased.y.to_numpy())
    assert count == 374 // 2

    # ================================== mixing factor = 1 ========================================
    biased1, subset = em.get_biased_subset(data,
                                           mixing_factor=1.0,
                                           unbiased_pcnt=0.5)
    # expected behavior: in biased1, s!=y everywhere; `subset` is just a subset of `data`

    assert biased1.s.shape == (188, 1)
    assert biased1.y.shape == (188, 1)
    assert (biased1.s.to_numpy() != biased1.y.to_numpy()).all()

    assert subset.s.shape[0] == approx(500, abs=4)
    assert subset.y.shape[0] == approx(500, abs=4)

    # the fraction of `data`points where y=s should be the same in the data and the subset
    subset_mean = (subset.s.to_numpy() == subset.y.to_numpy()).mean()
    assert subset_mean == approx(data_mean, abs=0.01)

    biased2, debiased = em.get_biased_and_debiased_subsets(data,
                                                           mixing_factor=1.0,
                                                           unbiased_pcnt=0.5,
                                                           fixed_unbiased=True)
    # expected behavior: in biased2, s!=y everywhere; in debiased, 50% s=y and 50% s!=y

    assert biased2.s.shape == (188, 1)
    assert biased2.y.shape == (188, 1)
    assert (biased2.s.to_numpy() != biased2.y.to_numpy()).all()

    assert debiased.s.shape == (374, 1)
    assert debiased.y.shape == (374, 1)
    # for the debiased subset, s=y half of the time
    count = np.count_nonzero(debiased.s.to_numpy() == debiased.y.to_numpy())
    assert count == 374 // 2