Repository: Aarhus-Psychiatry-Research/timeseriesflattener

Issue:
re-add tokens for GitHub actions
re-add tokens for GitHub actions. E.g. tokens for pytest, autopush to pypi and autoaccept dependabot.

Discussion:

Patch:
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 39d1132..f698334 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -1,4 +1,3 @@
-- [ ] I have battle-tested on Overtaci (RMAPPS1279)
 - [ ] I have assigned ranges (e.g. `>=0.1, <0.2`) to all new dependencies (allows dependabot to keep dependency ranges wide for better compatability)
 
 Fixes #[issue_nr_here].
diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml
index 9e15e58..54251fe 100644
--- a/.github/workflows/pre-commit.yml
+++ b/.github/workflows/pre-commit.yml
@@ -11,8 +11,10 @@ jobs:
   pre-commit:
     runs-on: ubuntu-latest
     steps:
-    - uses: actions/checkout@v3
-    - uses: actions/setup-python@v4
-      with:
-        python-version: '3.9' 
-    - uses: pre-commit/action@v3.0.0
\ No newline at end of file
+      - uses: actions/checkout@v3
+      - uses: actions/setup-python@v4
+        with:
+          python-version: "3.9"
+      - uses: pre-commit/action@v3.0.0
+        with:
+          extra_args: --hook-stage push --all-files
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 2cd7c1c..7b3ce38 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -13,16 +13,10 @@ repos:
     hooks:
       - id: pyupgrade
 
-  - repo: https://github.com/MartinBernstorff/pybetter-without-emojis
-    rev: 1208357bcc569b86a4a0dc69b108cbe28f190f54
-    hooks:
-    - id: pybetter
-      args: [--select, "B002,B007"]
-
   - repo: https://github.com/bwhmather/ssort
     rev: v0.11.6
     hooks:
-    - id: ssort
+      - id: ssort
 
   - repo: https://github.com/myint/docformatter
     rev: v1.5.0
@@ -45,10 +39,9 @@ repos:
     hooks:
       - id: pylint
         types: [python]
-        args:
-          [
+        args: [
             "-rn", # Only display messages
             "-sn", # Don't display the score
-            "--disable=R,import-error" # Refactors are not important enough to block a commit. 
-            # Unused-imports aren't testable by the github action, so don't test that here.
+            "--disable=R,import-error", # Refactors are not important enough to block a commit.
           ]
+# Unused-imports aren't testable by the github action, so don't test that here.
diff --git a/example/loaders/debug_loader_function.py b/example/loaders/debug_loader_function.py
deleted file mode 100644
index af51f49..0000000
--- a/example/loaders/debug_loader_function.py
+++ /dev/null
@@ -1,96 +0,0 @@
-"""Exemplifies how to debug an SQL loader function.
-
-Two primary purposes:
-1. Check the possible values the dataframe can contain and
-2. Check that the dataframe conforms to the required format.
-"""
-
-from typing import Any
-
-import pandas as pd
-
-import psycop_feature_generation.loaders.raw as raw_loaders
-from psycop_feature_generation.data_checks.raw.check_predictor_lists import check_raw_df
-
-
-def will_it_float(value: Any) -> bool:
-    """Check if a value can be converted to a float.
-
-    Args:
-        value (Any): A value.
-
-    Returns:
-        bool: True if the value can be converted to a float, False otherwise.
-    """
-    try:
-        float(value)
-        return True
-    except ValueError:
-        return False
-
-
-def get_prop_of_each_unique_value_for_non_floats(series: pd.Series) -> pd.Series:
-    """Get the proportion of each unique value in a series, but only for value
-    which cannot be converted to floats.
-
-    Args:
-        series (pd.Series): A pandas series.
-
-    Returns:
-        pd.Series: A series with the proportion of each unique value in the
-        original series.
-    """
-    if series.dtype in ["float64", "int64"]:
-        return "All values in series can be converted to floats."
-
-    # Find all strings that start with a number
-    starts_with_number_idx = series.str.match(r"^\d+").fillna(False)
-
-    # Convert all strings that start with a number to floats
-    # Replace all "," with "."
-    series[starts_with_number_idx] = series[starts_with_number_idx].str.replace(
-        ",",
-        ".",
-    )
-
-    # Convert all str in series to float
-    series[starts_with_number_idx] = series[starts_with_number_idx].astype(float)
-
-    # Get the unique values
-    unique_values = series.unique()
-
-    # Get the proportion of each unique value
-    prop_of_each_unique_value = series.value_counts(
-        normalize=True,
-    )
-
-    # Get the unique values which cannot be converted to floats
-    non_float_unique_values = [
-        value
-        for value in unique_values
-        if (not will_it_float(value) and value is not None)
-    ]
-
-    # Get the proportion of each unique value which cannot be converted to floats
-    prop_of_each_non_float_unique_value = prop_of_each_unique_value[
-        non_float_unique_values
-    ]
-
-    return prop_of_each_non_float_unique_value
-
-
-if __name__ == "__main__":
-    df = raw_loaders.load_lab_results.ldl(
-        n=1_000,
-        values_to_load="numerical_and_coerce",
-    )
-
-    value_props = get_prop_of_each_unique_value_for_non_floats(df["value"])
-    print(value_props)
-
-    errors, duplicates = check_raw_df(
-        df=df,
-        required_columns=["dw_ek_borger", "timestamp", "value"],
-        subset_duplicates_columns=["dw_ek_borger", "timestamp", "value"],
-    )
-    print(errors)
diff --git a/example/loaders/load_admissions.py b/example/loaders/load_admissions.py
deleted file mode 100644
index 23e0bc1..0000000
--- a/example/loaders/load_admissions.py
+++ /dev/null
@@ -1,7 +0,0 @@
-"""Example loader for admissions."""
-import psycop_feature_generation.loaders.raw as r
-
-if __name__ == "__main__":
-    df = r.load_admissions.admissions(n_rows=1000)
-    psych = r.load_admissions.admissions_to_psychiatry(n_rows=1000)
-    somatic = r.load_admissions.admissions_to_somatic(n_rows=1000)
diff --git a/example/loaders/load_bmi.py b/example/loaders/load_bmi.py
deleted file mode 100644
index 4160a81..0000000
--- a/example/loaders/load_bmi.py
+++ /dev/null
@@ -1,35 +0,0 @@
-"""Example of how to load demographic features."""
-import pandas as pd
-
-from psycop_feature_generation.loaders.raw.load_structured_sfi import (
-    bmi,
-    height_in_cm,
-    weight_in_kg,
-)
-from psycop_feature_generation.loaders.raw.sql_load import sql_load
-
-if __name__ == "__main__":
-    df = sql_load(
-        query="SELECT * FROM [fct].[FOR_SFI_vaegt_hoejde_BMI_psyk_somatik_inkl_2021]",
-        database="USR_PS_FORSK",
-        chunksize=None,
-        n_rows=1_000,
-    )[["aktivitetstypenavn", "elementledetekst", "numelementvaerdi", "elementvaerdi"]]
-
-    df_bmi = bmi(n_rows=1_000)
-    df_height = height_in_cm(n_rows=100_000)
-    df_weight = weight_in_kg(n_rows=100_000)
-
-
-def unique_and_percentage(series: pd.Series) -> pd.Series:
-    """Return unique values and their percentage of the total number of values
-    in the series.
-
-    Args:
-        series (pd.Series): Series to get unique values and percentage of.
-
-    Returns:
-        pd.Series: Series with unique values as index and percentage as values.
-    """
-    unique_values = series.value_counts(normalize=True)
-    return unique_values
diff --git a/example/loaders/load_coercion.py b/example/loaders/load_coercion.py
deleted file mode 100644
index 9e3c101..0000000
--- a/example/loaders/load_coercion.py
+++ /dev/null
@@ -1,11 +0,0 @@
-"""Testing loading of coercion functions."""
-
-# pylint: disable=non-ascii-name
-
-import psycop_feature_generation.loaders.raw.load_coercion as c
-
-if __name__ == "__main__":
-    df = c.coercion_duration(n_rows=100)
-    skema_2 = c.skema_2(n_rows=10000)
-    farlighed = c.farlighed(n_rows=20)
-    baelte = c.baelte(n_rows=100)
diff --git a/example/loaders/load_diagnoses.py b/example/loaders/load_diagnoses.py
deleted file mode 100644
index 211c54d..0000000
--- a/example/loaders/load_diagnoses.py
+++ /dev/null
@@ -1,6 +0,0 @@
-"""Example for loading diagnoses."""
-
-import psycop_feature_generation.loaders.raw.load_diagnoses as d
-
-if __name__ == "__main__":
-    df = d.gerd(n_rows=200)
diff --git a/example/loaders/load_medications.py b/example/loaders/load_medications.py
deleted file mode 100644
index a8b4523..0000000
--- a/example/loaders/load_medications.py
+++ /dev/null
@@ -1,6 +0,0 @@
-"""Example of loading medications."""
-
-import psycop_feature_generation.loaders.raw.load_medications as m
-
-if __name__ == "__main__":
-    df = m.antipsychotics(n_rows=500)
diff --git a/example/loaders/load_physical_visits.py b/example/loaders/load_physical_visits.py
deleted file mode 100644
index 6219b4d..0000000
--- a/example/loaders/load_physical_visits.py
+++ /dev/null
@@ -1,7 +0,0 @@
-"""Example loader for physical visits."""
-import psycop_feature_generation.loaders.raw as r
-
-if __name__ == "__main__":
-    df = r.load_visits.physical_visits(n_rows=1000)
-    psych = r.load_visits.physical_visits_to_psychiatry(n_rows=1000)
-    somatic = r.load_visits.physical_visits_to_somatic(n_rows=1000)
diff --git a/example/loaders/load_sql.py b/example/loaders/load_sql.py
deleted file mode 100644
index 80a18b8..0000000
--- a/example/loaders/load_sql.py
+++ /dev/null
@@ -1,8 +0,0 @@
-"""Example of how to load IDs from sql."""
-
-from psycop_feature_generation.loaders.raw.sql_load import sql_load
-
-if __name__ == "__main__":
-    VIEW = "[psycop_t2d_train]"
-    SQL = "SELECT * FROM [fct]." + VIEW
-    df = sql_load(SQL, chunksize=None, format_timestamp_cols_to_datetime=False)
diff --git a/example/loaders/load_structured_sfi.py b/example/loaders/load_structured_sfi.py
deleted file mode 100644
index 39706d0..0000000
--- a/example/loaders/load_structured_sfi.py
+++ /dev/null
@@ -1,21 +0,0 @@
-"""Example for loading structured SFIs."""
-
-import psycop_feature_generation.loaders.raw.load_structured_sfi as struct_sfi_loader
-from psycop_feature_generation.data_checks.raw.check_predictor_lists import (
-    check_feature_combinations_return_correct_dfs,
-)
-
-if __name__ == "__main__":
-    df = struct_sfi_loader.selvmordsrisiko(n_rows=1000)
-
-    input_dict = [
-        {
-            "predictor_df": "selvmordsrisiko",
-            "allowed_nan_value_prop": 0.01,
-        },
-    ]
-
-    check_feature_combinations_return_correct_dfs(
-        predictor_dict_list=input_dict,
-        n_rows=1000,
-    )
diff --git a/pyproject.toml b/pyproject.toml
index e658401..1741639 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,9 +1,9 @@
 [tool.poetry]
 name = "timeseriesflattener"
-version = "0.10.0"
+version = "0.10.1"
 description = "A package for converting time series data from e.g. electronic health records into wide format data."
 readme = "README.md"
-authors = ["Martin Bernstorff", "Kenneth Enevoldsen",  "Jakob Grøhn Damgaard", "Frida Hæstrup", "Lasse Hansen"]
+authors = ["Martin Bernstorff", "Kenneth Enevoldsen", "Jakob Grøhn Damgaard", "Frida Hæstrup", "Lasse Hansen"]
 
 [tool.poetry.dependencies]
 python = ">=3.9, <3.11"
@@ -57,6 +57,7 @@ known_third_party = ["wandb"]
 load-plugins = "pylint.extensions.docparams,pylint.extensions.code_style,pylint.extensions.for_any_all,pylint.extensions.typing"
 good-names = "df,p,f,d,e,n,k,i,v"
 disable = "too-many-lines,line-too-long,missing-raises-doc,no-self-argument,unused-wildcard-import,wildcard-import,no-else-return,too-many-arguments,redefined-outer-name,c-extension-no-member,wrong-import-order"
+ignore-paths = ['docs/*']
 
 [tool.semantic_release]
 branch = "main"
@@ -73,4 +74,4 @@ n = 0
 [tool.mypy]
 ignore_missing_imports = true
 
-[tool.pyright] # Added because of weird pylance error, issue here: https://github.com/microsoft/pylance-release/issues/3366
+[tool.pyright] # Added because of weird pylance error, issue here: https://github.com/microsoft/pylance-release/issues/3366
\ No newline at end of file
diff --git a/src/application/t2d/check_flattened_ds_integrity.py b/src/application/t2d/check_flattened_ds_integrity.py
deleted file mode 100644
index 2a1e9b6..0000000
--- a/src/application/t2d/check_flattened_ds_integrity.py
+++ /dev/null
@@ -1,18 +0,0 @@
-"""Example for how to check feature set integrity."""
-
-from pathlib import Path
-
-from psycop_feature_generation.data_checks.flattened.data_integrity import (
-    save_feature_set_integrity_from_dir,
-)
-
-if __name__ == "__main__":
-    subdir = Path(
-        "E:/shared_resources/feature_sets/t2d/adminmanber_260_features_2022_08_26_14_10/",
-    )
-
-    save_feature_set_integrity_from_dir(
-        feature_set_dir=subdir,
-        split_names=["train", "val", "test"],
-        file_suffix=".parquet",
-    )
diff --git a/src/application/t2d/generate_features_and_write_to_disk.py b/src/application/t2d/generate_features_and_write_to_disk.py
deleted file mode 100644
index 7e8ae01..0000000
--- a/src/application/t2d/generate_features_and_write_to_disk.py
+++ /dev/null
@@ -1,651 +0,0 @@
-"""Main example on how to generate features.
-
-Uses T2D-features. WIP, will be migrated to psycop-t2d when reaching
-maturity.
-"""
-
-import sys
-import tempfile
-import time
-from collections.abc import Sequence
-from multiprocessing import Pool
-from pathlib import Path
-from typing import Callable, Optional, Union
-
-import numpy as np
-import pandas as pd
-import psutil
-import wandb
-from wasabi import Printer
-
-import psycop_feature_generation.loaders.raw  # noqa
-from psycop_feature_generation.data_checks.flattened.data_integrity import (
-    save_feature_set_integrity_from_dir,
-)
-from psycop_feature_generation.data_checks.flattened.feature_describer import (
-    save_feature_description_from_dir,
-)
-from psycop_feature_generation.loaders.raw.load_demographic import birthdays
-from psycop_feature_generation.loaders.raw.load_visits import (
-    physical_visits_to_psychiatry,
-)
-from psycop_feature_generation.timeseriesflattener.feature_spec_objects import (
-    AnySpec,
-    BaseModel,
-    OutcomeGroupSpec,
-    OutcomeSpec,
-    PredictorGroupSpec,
-    PredictorSpec,
-    StaticSpec,
-    TemporalSpec,
-)
-from psycop_feature_generation.timeseriesflattener.flattened_dataset import (
-    FlattenedDataset,
-)
-from psycop_feature_generation.utils import (
-    FEATURE_SETS_PATH,
-    N_WORKERS,
-    PROJECT_ROOT,
-    write_df_to_file,
-)
-
-LOOKAHEAD_YEARS = (1, 2, 3, 4, 5)
-msg = Printer(timestamp=True)
-
-
-def init_wandb(
-    wandb_project_name: str,
-    predictor_specs: Sequence[PredictorSpec],
-    save_dir: Union[Path, str],
-) -> None:
-    """Initialise wandb logging. Allows to use wandb to track progress, send
-    Slack notifications if failing, and track logs.
-
-    Args:
-        wandb_project_name (str): Name of wandb project.
-        predictor_specs (Iterable[dict[str, Any]]): List of predictor specs.
-        save_dir (Union[Path, str]): Path to save dir.
-    """
-
-    feature_settings = {
-        "save_path": save_dir,
-        "predictor_list": [spec.__dict__ for spec in predictor_specs],
-    }
-
-    # on Overtaci, the wandb tmp directory is not automatically created,
-    # so we create it here.
-    # create debug-cli.one folders in /tmp and project dir
-    if sys.platform == "win32":
-        (Path(tempfile.gettempdir()) / "debug-cli.onerm").mkdir(
-            exist_ok=True,
-            parents=True,
-        )
-        (PROJECT_ROOT / "wandb" / "debug-cli.onerm").mkdir(exist_ok=True, parents=True)
-
-    wandb.init(project=wandb_project_name, config=feature_settings)
-
-
-def save_feature_set_description_to_disk(
-    predictor_specs: list,
-    flattened_dataset_file_dir: Path,
-    out_dir: Path,
-    file_suffix: str,
-    describe_splits: bool = True,
-    compare_splits: bool = True,
-):
-    """Describe output.
-
-    Args:
-        predictor_specs (list): List of predictor specs.
-        flattened_dataset_file_dir (Path): Path to dir containing flattened time series files.
-        out_dir (Path): Path to output dir.
-        file_suffix (str): File suffix.
-        describe_splits (bool, optional): Whether to describe each split. Defaults to True.
-        compare_splits (bool, optional): Whether to compare splits, e.g. do all categories exist in both train and val. Defaults to True.
-    """
-
-    # Create data integrity report
-    if describe_splits:
-        save_feature_description_from_dir(
-            feature_set_dir=flattened_dataset_file_dir,
-            feature_specs=predictor_specs,
-            splits=["train"],
-            out_dir=out_dir,
-            file_suffix=file_suffix,
-        )
-
-    # Describe/compare splits control flow happens within this function
-    if compare_splits:
-        save_feature_set_integrity_from_dir(
-            feature_set_dir=flattened_dataset_file_dir,
-            split_names=["train", "val", "test"],
-            out_dir=out_dir,
-            file_suffix=file_suffix,
-            describe_splits=describe_splits,
-            compare_splits=compare_splits,
-        )
-
-
-def create_save_dir_path(
-    proj_path: Path,
-    feature_set_id: str,
-) -> Path:
-    """Create save directory.
-
-    Args:
-        proj_path (Path): Path to project.
-        feature_set_id (str): Feature set id.
-
-    Returns:
-        Path: Path to sub directory.
-    """
-
-    # Split and save to disk
-    # Create directory to store all files related to this run
-    save_dir = proj_path / "feature_sets" / feature_set_id
-
-    if not save_dir.exists():
-        save_dir.mkdir()
-
-    return save_dir
-
-
-def split_and_save_dataset_to_disk(
-    flattened_df: pd.DataFrame,
-    out_dir: Path,
-    file_prefix: str,
-    file_suffix: str,
-    split_ids_dict: Optional[dict[str, pd.Series]] = None,
-    splits: Optional[list[str]] = None,
-):
-    """Split and save to disk.
-
-    Args:
-        flattened_df (pd.DataFrame): Flattened dataframe.
-        out_dir (Path): Path to output directory.
-        file_prefix (str): File prefix.
-        file_suffix (str, optional): Format to save to. Takes any of ["parquet", "csv"].
-        split_ids_dict (Optional[dict[str, list[str]]]): Dictionary of split ids, like {"train": pd.Series with ids}.
-        splits (list, optional): Which splits to create. Defaults to ["train", "val", "test"].
-    """
-
-    if splits is None:
-        splits = ["train", "val", "test"]
-
-    msg = Printer(timestamp=True)
-
-    flattened_df_ids = flattened_df["dw_ek_borger"].unique()
-
-    # Version table with current date and time
-    # prefix with user name to avoid potential clashes
-
-    # Create splits
-    for dataset_name in splits:
-        if split_ids_dict is None:
-            df_split_ids = psycop_feature_generation.loaders.raw.load_ids(
-                split=dataset_name,
-            )
-        else:
-            df_split_ids = split_ids_dict[dataset_name]
-
-        # Find IDs which are in split_ids, but not in flattened_df
-        split_ids = df_split_ids["dw_ek_borger"].unique()
-        flattened_df_ids = flattened_df["dw_ek_borger"].unique()
-
-        ids_in_split_but_not_in_flattened_df = split_ids[
-            ~np.isin(split_ids, flattened_df_ids)
-        ]
-
-        msg.warn(
-            f"{dataset_name}: There are {len(ids_in_split_but_not_in_flattened_df)} ({round(len(ids_in_split_but_not_in_flattened_df) / len(split_ids) * 100, 2)}%) ids which are in {dataset_name}_ids but not in flattened_df_ids, will get dropped during merge. If examining patients based on physical visits, see 'OBS: Patients without physical visits' on the wiki for more info.",
-        )
-
-        split_df = pd.merge(flattened_df, df_split_ids, how="inner", validate="m:1")
-
-        # Version table with current date and time
-        filename = f"{file_prefix}_{dataset_name}.{file_suffix}"
-        msg.info(f"Saving {filename} to disk")
-
-        file_path = out_dir / filename
-
-        write_df_to_file(df=split_df, file_path=file_path)
-
-        msg.good(f"{dataset_name}: Succesfully saved to {file_path}")
-
-
-def add_metadata_to_ds(
-    specs: list[AnySpec],
-    flattened_dataset: FlattenedDataset,
-) -> FlattenedDataset:
-    """Add metadata.
-
-    Args:
-        specs (list[AnySpec]): List of specifications.
-        flattened_dataset (FlattenedDataset): Flattened dataset.
-
-    Returns:
-        FlattenedDataset: Flattened dataset.
-    """
-    msg.info("Adding metadata to dataset")
-
-    for spec in specs:
-        msg.info(f"Adding metadata from {spec.feature_name}")
-        if isinstance(spec, StaticSpec):
-            flattened_dataset.add_static_info(
-                static_spec=spec,
-            )
-        elif isinstance(spec, TemporalSpec):
-            flattened_dataset.add_temporal_predictor(output_spec=spec)
-
-    return flattened_dataset
-
-
-def add_outcomes_to_ds(
-    flattened_dataset: FlattenedDataset,
-    outcome_specs: list[OutcomeSpec],
-) -> FlattenedDataset:
-    """Add outcomes.
-
-    Args:
-        flattened_dataset (FlattenedDataset): Flattened dataset.
-        outcome_specs (list[OutcomeSpec]): List of outcome specifications.
-
-    Returns:
-        FlattenedDataset: Flattened dataset.
-    """
-    msg.info("Adding outcomes to dataset")
-
-    for spec in outcome_specs:
-        msg.info(f"Adding outcome with {spec.interval_days} days of lookahead")
-        flattened_dataset.add_temporal_outcome(
-            output_spec=spec,
-        )
-
-    msg.good("Finished adding outcomes")
-
-    return flattened_dataset
-
-
-def add_predictors_to_ds(
-    temporal_predictor_specs: list[PredictorSpec],
-    static_predictor_specs: list[AnySpec],
-    birthdays: pd.DataFrame,
-    flattened_dataset: FlattenedDataset,
-):
-    """Add predictors.
-
-    Args:
-        temporal_predictor_specs (list[PredictorSpec]): List of predictor specs.
-        static_predictor_specs (list[StaticSpec]): List of static specs.
-        birthdays (pd.DataFrame): Birthdays. Used for inferring age at each prediction time.
-        flattened_dataset (FlattenedDataset): Flattened dataset.
-    """
-    msg = Printer(timestamp=True)
-
-    msg.info("Adding static predictors")
-
-    for static_spec in static_predictor_specs:
-        flattened_dataset.add_static_info(
-            static_spec=static_spec,
-        )
-
-    flattened_dataset.add_age_and_birth_year(
-        id2date_of_birth=birthdays, birth_year_as_predictor=True
-    )
-
-    start_time = time.time()
-
-    msg.info("Adding temporal predictors")
-    flattened_dataset.add_temporal_predictors_from_pred_specs(
-        predictor_specs=temporal_predictor_specs,
-    )
-
-    end_time = time.time()
-
-    # Finish
-    msg.good(
-        f"Finished adding {len(temporal_predictor_specs)} predictors, took {round((end_time - start_time) / 60, 1)} minutes",
-    )
-
-    return flattened_dataset
-
-
-def resolve_spec_set_component(spec_set_component: dict[str, Callable]):
-    for k, v in spec_set_component.items():
-        spec_set_component[k] = v()
-
-    return spec_set_component
-
-
-class SpecSet(BaseModel):
-    """A set of unresolved specs, ready for resolving."""
-
-    temporal_predictors: list[PredictorSpec]
-    static_predictors: list[StaticSpec]
-    outcomes: list[OutcomeSpec]
-    metadata: list[AnySpec]
-
-
-def create_flattened_dataset(
-    prediction_times: pd.DataFrame,
-    birthdays: pd.DataFrame,
-    spec_set: SpecSet,
-    proj_path: Path,
-) -> pd.DataFrame:
-    """Create flattened dataset.
-
-    Args:
-        prediction_times (pd.DataFrame): Dataframe with prediction times.
-        birthdays (pd.DataFrame): Birthdays. Used for inferring age at each prediction time.
-        spec_set (SpecSet): Set of specifications.
-        proj_path (Path): Path to project directory.
-
-    Returns:
-        FlattenedDataset: Flattened dataset.
-    """
-
-    msg.info(f"Generating {len(spec_set.temporal_predictors)} features")
-
-    msg.info("Initialising flattened dataset")
-
-    flattened_dataset = FlattenedDataset(
-        prediction_times_df=prediction_times,
-        n_workers=min(
-            len(spec_set.temporal_predictors),
-            50,
-        ),
-        feature_cache_dir=proj_path / "feature_cache",
-    )
-
-    flattened_dataset = add_predictors_to_ds(
-        temporal_predictor_specs=spec_set.temporal_predictors,
-        static_predictor_specs=spec_set.static_predictors,
-        flattened_dataset=flattened_dataset,
-        birthdays=birthdays,
-    )
-
-    flattened_dataset = add_metadata_to_ds(
-        flattened_dataset=flattened_dataset,
-        specs=spec_set.metadata,
-    )
-
-    flattened_dataset = add_outcomes_to_ds(
-        outcome_specs=spec_set.outcomes,
-        flattened_dataset=flattened_dataset,
-    )
-
-    return flattened_dataset.df
-
-
-def setup_for_main(
-    n_predictors: int,
-    feature_sets_path: Path,
-    proj_name: str,
-) -> tuple[Path, str]:
-    """Setup for main.
-
-    Args:
-        n_predictors (int): Number of predictors.
-        feature_sets_path (Path): Path to feature sets.
-        proj_name (str): Name of project.
-    Returns:
-        tuple[Path, str]: Tuple of project path, and feature_set_id
-    """
-    proj_path = feature_sets_path / proj_name
-
-    if not proj_path.exists():
-        proj_path.mkdir()
-
-    current_user = Path().home().name
-    feature_set_id = f"psycop_{proj_name}_{current_user}_{n_predictors}_features_{time.strftime('%Y_%m_%d_%H_%M')}"
-
-    return proj_path, feature_set_id
-
-
-def get_static_predictor_specs():
-    """Get static predictor specs."""
-    return [
-        StaticSpec(
-            values_loader="sex_female",
-            input_col_name_override="sex_female",
-            prefix="pred",
-        ),
-    ]
-
-
-def get_metadata_specs() -> list[AnySpec]:
-    """Get metadata specs."""
-    metadata_specs = [
-        StaticSpec(
-            values_loader="t2d",
-            input_col_name_override="timestamp",
-            output_col_name_override="timestamp_first_t2d_hba1c",
-        ),
-        StaticSpec(
-            values_loader="timestamp_exclusion",
-            input_col_name_override="timestamp",
-            output_col_name_override="timestamp_exclusion",
-        ),
-        PredictorSpec(
-            values_loader="hba1c",
-            fallback=np.nan,
-            interval_days=9999,
-            resolve_multiple_fn="count",
-            allowed_nan_value_prop=0.0,
-            prefix="eval",
-        ),
-    ]
-
-    metadata_specs += OutcomeGroupSpec(
-        values_loader=["hba1c"],
-        interval_days=[year * 365 for year in LOOKAHEAD_YEARS],
-        resolve_multiple_fn=["count"],
-        fallback=[0],
-        incident=[False],
-        allowed_nan_value_prop=[0.0],
-        prefix="eval",
-    ).create_combinations()
-
-    return metadata_specs
-
-
-def get_outcome_specs():
-    """Get outcome specs."""
-    return OutcomeGroupSpec(
-        values_loader=["t2d"],
-        interval_days=[year * 365 for year in LOOKAHEAD_YEARS],
-        resolve_multiple_fn=["max"],
-        fallback=[0],
-        incident=[True],
-        allowed_nan_value_prop=[0],
-    ).create_combinations()
-
-
-def resolve_group_spec(group_spec: Union[PredictorGroupSpec, OutcomeGroupSpec]):
-    return group_spec.create_combinations()
-
-
-def get_temporal_predictor_specs() -> list[PredictorSpec]:
-    """Generate predictor spec list."""
-    base_resolve_multiple = ["max", "min", "mean", "latest", "count"]
-    base_interval_days = [30, 90, 180, 365, 730]
-    base_allowed_nan_value_prop = [0]
-
-    temporal_predictor_groups = [
-        PredictorGroupSpec(
-            values_loader=(
-                "alat",
-                "hdl",
-                "ldl",
-                "triglycerides",
-                "fasting_ldl",
-                "crp",
-            ),
-            resolve_multiple_fn=base_resolve_multiple,
-            interval_days=base_interval_days,
-            fallback=[np.nan],
-            allowed_nan_value_prop=base_allowed_nan_value_prop,
-        ),
-        PredictorGroupSpec(
-            values_loader=(
-                "hba1c",
-                "scheduled_glc",
-                "unscheduled_p_glc",
-                "egfr",
-                "albumine_creatinine_ratio",
-            ),
-            resolve_multiple_fn=base_resolve_multiple,
-            interval_days=base_interval_days,
-            fallback=[np.nan],
-            allowed_nan_value_prop=base_allowed_nan_value_prop,
-        ),
-        PredictorGroupSpec(
-            values_loader=(
-                "essential_hypertension",
-                "hyperlipidemia",
-                "polycystic_ovarian_syndrome",
-                "sleep_apnea",
-                "gerd",
-            ),
-            resolve_multiple_fn=base_resolve_multiple,
-            interval_days=base_interval_days,
-            fallback=[0],
-            allowed_nan_value_prop=base_allowed_nan_value_prop,
-        ),
-        PredictorGroupSpec(
-            values_loader=(
-                "f0_disorders",
-                "f1_disorders",
-                "f2_disorders",
-                "f3_disorders",
-                "f4_disorders",
-                "f5_disorders",
-                "f6_disorders",
-                "f7_disorders",
-                "f8_disorders",
-                "hyperkinetic_disorders",
-            ),
-            resolve_multiple_fn=base_resolve_multiple,
-            interval_days=base_interval_days,
-            fallback=[0],
-            allowed_nan_value_prop=base_allowed_nan_value_prop,
-        ),
-        PredictorGroupSpec(
-            values_loader=(
-                "antipsychotics",
-                "clozapine",
-                "top_10_weight_gaining_antipsychotics",
-                "lithium",
-                "valproate",
-                "lamotrigine",
-                "benzodiazepines",
-                "pregabaline",
-                "ssri",
-                "snri",
-                "tca",
-                "selected_nassa",
-                "benzodiazepine_related_sleeping_agents",
-            ),
-            interval_days=base_interval_days,
-            resolve_multiple_fn=base_resolve_multiple,
-            fallback=[0],
-            allowed_nan_value_prop=base_allowed_nan_value_prop,
-        ),
-        PredictorGroupSpec(
-            values_loader=(
-                "gerd_drugs",
-                "statins",
-                "antihypertensives",
-                "diuretics",
-            ),
-            interval_days=base_interval_days,
-            resolve_multiple_fn=base_resolve_multiple,
-            fallback=[0],
-            allowed_nan_value_prop=base_allowed_nan_value_prop,
-        ),
-        PredictorGroupSpec(
-            values_loader=["weight_in_kg", "height_in_cm", "bmi"],
-            interval_days=base_interval_days,
-            resolve_multiple_fn=["latest"],
-            fallback=[np.nan],
-            allowed_nan_value_prop=base_allowed_nan_value_prop,
-        ),
-    ]
-
-    with Pool(min(N_WORKERS, len(temporal_predictor_groups))) as p:
-        temporal_predictor_specs: list[PredictorSpec] = p.map(
-            func=resolve_group_spec, iterable=temporal_predictor_groups
-        )
-
-        # Unpack list of lists
-        temporal_predictor_specs = [
-            item for sublist in temporal_predictor_specs for item in sublist
-        ]
-
-    return temporal_predictor_specs
-
-
-def main(
-    proj_name: str,
-    feature_sets_path: Path,
-):
-    """Main function for loading, generating and evaluating a flattened
-    dataset.
-
-    Args:
-        proj_name (str): Name of project.
-        feature_sets_path (Path): Path to where feature sets should be stored.
-    """
-    spec_set = SpecSet(
-        temporal_predictors=get_temporal_predictor_specs(),
-        static_predictors=get_static_predictor_specs(),
-        outcomes=get_outcome_specs(),
-        metadata=get_metadata_specs(),
-    )
-
-    proj_path, feature_set_id = setup_for_main(
-        n_predictors=len(spec_set.temporal_predictors),
-        feature_sets_path=feature_sets_path,
-        proj_name=proj_name,
-    )
-
-    out_dir = create_save_dir_path(
-        feature_set_id=feature_set_id,
-        proj_path=proj_path,
-    )
-
-    init_wandb(
-        wandb_project_name=proj_name,
-        predictor_specs=spec_set.temporal_predictors,
-        save_dir=out_dir,  # Save-dir as argument because we want to log the path
-    )
-
-    flattened_df = create_flattened_dataset(
-        prediction_times=physical_visits_to_psychiatry(),
-        spec_set=spec_set,
-        proj_path=proj_path,
-        birthdays=birthdays(),
-    )
-
-    split_and_save_dataset_to_disk(
-        flattened_df=flattened_df,
-        out_dir=out_dir,
-        file_prefix=feature_set_id,
-        file_suffix="parquet",
-    )
-
-    save_feature_set_description_to_disk(
-        predictor_specs=spec_set.temporal_predictors + spec_set.static_predictors,
-        flattened_dataset_file_dir=out_dir,
-        out_dir=out_dir,
-        file_suffix="parquet",
-    )
-
-    wandb.log_artifact("poetry.lock", name="poetry_lock_file", type="poetry_lock")
-
-
-if __name__ == "__main__":
-    main(
-        feature_sets_path=FEATURE_SETS_PATH,
-        proj_name="t2d",
-    )
diff --git a/src/application/__init__.py b/src/data_checks/__init__.py
similarity index 100%
rename from src/application/__init__.py
rename to src/data_checks/__init__.py
diff --git a/src/timeseriesflattener/data_checks/flattened/data_integrity.py b/src/data_checks/flattened/data_integrity.py
similarity index 98%
rename from src/timeseriesflattener/data_checks/flattened/data_integrity.py
rename to src/data_checks/flattened/data_integrity.py
index c17ff5b..54d240f 100644
--- a/src/timeseriesflattener/data_checks/flattened/data_integrity.py
+++ b/src/data_checks/flattened/data_integrity.py
@@ -25,14 +25,12 @@ from deepchecks.tabular.checks import (
 )
 from wasabi import Printer
 
-from psycop_feature_generation.loaders.flattened import (
-    load_split_outcomes,
-    load_split_predictors,
-)
+from loaders.flattened import load_split_outcomes, load_split_predictors
 
 
 def pruned_data_integrity_checks(**kwargs) -> Suite:
     """Deepchecks data integrity suite with only wanted checks.
+
     Disables: SpecialCharacters, StringMismatch, ConflictingLabels.
 
     Args:
@@ -78,8 +76,9 @@ def label_integrity_checks() -> Suite:
 
 
 def custom_train_test_validation(**kwargs) -> Suite:
-    """Deepchecks train/test validation suite for train/test checks which slow
-    checks disabled.
+    """Deepchecks train/test validation suite.
+
+    Slow checks disabled.
 
     Args:
         **kwargs: Keyword arguments to pass to the Suite constructor.
diff --git a/src/timeseriesflattener/data_checks/flattened/feature_describer.py b/src/data_checks/flattened/feature_describer.py
similarity index 93%
rename from src/timeseriesflattener/data_checks/flattened/feature_describer.py
rename to src/data_checks/flattened/feature_describer.py
index 094b951..4780f9b 100644
--- a/src/timeseriesflattener/data_checks/flattened/feature_describer.py
+++ b/src/data_checks/flattened/feature_describer.py
@@ -2,22 +2,14 @@
 df."""
 from collections.abc import Sequence
 from pathlib import Path
-from typing import Union
 
 import numpy as np
 import pandas as pd
 from wasabi import Printer
 
-from psycop_feature_generation.data_checks.utils import save_df_to_pretty_html_table
-from psycop_feature_generation.loaders.flattened.local_feature_loaders import (
-    load_split_predictors,
-)
-from psycop_feature_generation.timeseriesflattener.feature_spec_objects import (
-    AnySpec,
-    PredictorSpec,
-    StaticSpec,
-    TemporalSpec,
-)
+from data_checks.utils import save_df_to_pretty_html_table
+from loaders.flattened.local_feature_loaders import load_split_predictors
+from timeseriesflattener.feature_spec_objects import AnySpec, StaticSpec, TemporalSpec
 
 UNICODE_HIST = {
     0: " ",
@@ -156,7 +148,7 @@ def generate_feature_description_row(
 
 def generate_feature_description_df(
     df: pd.DataFrame,
-    predictor_specs: list[PredictorSpec],
+    predictor_specs: list[AnySpec],
 ) -> pd.DataFrame:
     """Generate a data frame with feature descriptions.
 
@@ -191,10 +183,10 @@ def generate_feature_description_df(
 
 def save_feature_description_from_dir(
     feature_set_dir: Path,
-    feature_specs: list[Union[TemporalSpec, StaticSpec]],
+    feature_specs: list[AnySpec],
     file_suffix: str,
+    out_dir: Path,
     splits: Sequence[str] = ("train",),
-    out_dir: Path = None,
 ):
     """Write a csv with feature descriptions in the directory.
 
@@ -202,8 +194,8 @@ def save_feature_description_from_dir(
         feature_set_dir (Path): Path to directory with data frames.
         feature_specs (list[PredictorSpec]): List of feature specifications.
         file_suffix (str): Suffix of the data frames to load. Must be either ".csv" or ".parquet".
-        splits (tuple[str]): tuple of splits to include in the description. Defaults to ("train").
         out_dir (Path): Path to directory where to save the feature description. Defaults to None.
+        splits (tuple[str]): tuple of splits to include in the description. Defaults to ("train").
     """
     msg = Printer(timestamp=True)
 
diff --git a/src/timeseriesflattener/data_checks/raw/check_predictor_lists.py b/src/data_checks/raw/check_predictor_lists.py
similarity index 98%
rename from src/timeseriesflattener/data_checks/raw/check_predictor_lists.py
rename to src/data_checks/raw/check_predictor_lists.py
index 2fae584..479d02d 100644
--- a/src/timeseriesflattener/data_checks/raw/check_predictor_lists.py
+++ b/src/data_checks/raw/check_predictor_lists.py
@@ -7,8 +7,8 @@ from typing import Optional, Union
 import pandas as pd
 from wasabi import Printer
 
-from psycop_feature_generation.data_checks.raw.check_raw_df import check_raw_df
-from psycop_feature_generation.utils import data_loaders
+from data_checks.raw.check_raw_df import check_raw_df
+from timeseriesflattener.utils import data_loaders
 
 
 def check_df_conforms_to_feature_spec(
diff --git a/src/timeseriesflattener/data_checks/raw/check_raw_df.py b/src/data_checks/raw/check_raw_df.py
similarity index 100%
rename from src/timeseriesflattener/data_checks/raw/check_raw_df.py
rename to src/data_checks/raw/check_raw_df.py
diff --git a/src/timeseriesflattener/data_checks/raw/validate_raw_data.py b/src/data_checks/raw/validate_raw_data.py
similarity index 95%
rename from src/timeseriesflattener/data_checks/raw/validate_raw_data.py
rename to src/data_checks/raw/validate_raw_data.py
index 7f5ca16..edf4dee 100644
--- a/src/timeseriesflattener/data_checks/raw/validate_raw_data.py
+++ b/src/data_checks/raw/validate_raw_data.py
@@ -9,14 +9,10 @@ from deepchecks.tabular import Dataset
 from deepchecks.tabular.suites import data_integrity
 from wasabi import Printer
 
-from psycop_feature_generation.data_checks.flattened.data_integrity import (
-    get_failed_check_names,
-)
-from psycop_feature_generation.data_checks.flattened.feature_describer import (
-    create_unicode_hist,
-)
-from psycop_feature_generation.data_checks.utils import save_df_to_pretty_html_table
-from psycop_feature_generation.utils import RAW_DATA_VALIDATION_PATH
+from data_checks.flattened.data_integrity import get_failed_check_names
+from data_checks.flattened.feature_describer import create_unicode_hist
+from data_checks.utils import save_df_to_pretty_html_table
+from timeseriesflattener.utils import RAW_DATA_VALIDATION_PATH
 
 
 def median_absolute_deviation(series: pd.Series) -> float:
diff --git a/src/timeseriesflattener/data_checks/utils.py b/src/data_checks/utils.py
similarity index 100%
rename from src/timeseriesflattener/data_checks/utils.py
rename to src/data_checks/utils.py
diff --git a/src/application/t2d/__init__.py b/src/loaders/__init__.py
similarity index 100%
rename from src/application/t2d/__init__.py
rename to src/loaders/__init__.py
diff --git a/src/timeseriesflattener/loaders/flattened/__init__.py b/src/loaders/flattened/__init__.py
similarity index 100%
rename from src/timeseriesflattener/loaders/flattened/__init__.py
rename to src/loaders/flattened/__init__.py
diff --git a/src/timeseriesflattener/loaders/flattened/local_feature_loaders.py b/src/loaders/flattened/local_feature_loaders.py
similarity index 98%
rename from src/timeseriesflattener/loaders/flattened/local_feature_loaders.py
rename to src/loaders/flattened/local_feature_loaders.py
index 5695614..370721d 100644
--- a/src/timeseriesflattener/loaders/flattened/local_feature_loaders.py
+++ b/src/loaders/flattened/local_feature_loaders.py
@@ -5,7 +5,7 @@ from typing import Optional
 
 import pandas as pd
 
-from psycop_feature_generation.utils import load_dataset_from_file
+from timeseriesflattener.utils import load_dataset_from_file
 
 
 def get_predictors(df: pd.DataFrame, include_id: bool) -> pd.DataFrame:
diff --git a/src/timeseriesflattener/loaders/synth/raw/load_synth_data.py b/src/loaders/synth/raw/load_synth_data.py
similarity index 96%
rename from src/timeseriesflattener/loaders/synth/raw/load_synth_data.py
rename to src/loaders/synth/raw/load_synth_data.py
index b7a605d..3d5e371 100644
--- a/src/timeseriesflattener/loaders/synth/raw/load_synth_data.py
+++ b/src/loaders/synth/raw/load_synth_data.py
@@ -4,7 +4,7 @@ from typing import Optional
 
 import pandas as pd
 
-from psycop_feature_generation.utils import PROJECT_ROOT, data_loaders
+from timeseriesflattener.utils import PROJECT_ROOT, data_loaders
 
 
 def load_raw_test_csv(filename: str, n_rows: Optional[int] = None) -> pd.DataFrame:
diff --git a/src/timeseriesflattener/__init__.py b/src/timeseriesflattener/__init__.py
index e69de29..c4eae1f 100644
--- a/src/timeseriesflattener/__init__.py
+++ b/src/timeseriesflattener/__init__.py
@@ -0,0 +1,2 @@
+"""Init timeseriesflattener."""
+from .flattened_dataset import FlattenedDataset
diff --git a/src/timeseriesflattener/data_checks/__init__.py b/src/timeseriesflattener/data_checks/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/timeseriesflattener/timeseriesflattener/feature_spec_objects.py b/src/timeseriesflattener/feature_spec_objects.py
similarity index 90%
rename from src/timeseriesflattener/timeseriesflattener/feature_spec_objects.py
rename to src/timeseriesflattener/feature_spec_objects.py
index 623e862..427c496 100644
--- a/src/timeseriesflattener/timeseriesflattener/feature_spec_objects.py
+++ b/src/timeseriesflattener/feature_spec_objects.py
@@ -1,9 +1,9 @@
 """Templates for feature specifications."""
 
 import itertools
-from collections.abc import Sequence
+from collections.abc import Callable, Sequence
 from functools import cache
-from typing import Any, Callable, Optional, Union
+from typing import Any, Optional, Union
 
 import pandas as pd
 from frozendict import frozendict  # type: ignore
@@ -11,18 +11,19 @@ from pydantic import BaseModel as PydanticBaseModel
 from pydantic import Extra
 from wasabi import Printer
 
-from psycop_feature_generation.timeseriesflattener.resolve_multiple_functions import (
-    resolve_multiple_fns,
-)
-from psycop_feature_generation.utils import data_loaders
+from timeseriesflattener.resolve_multiple_functions import resolve_multiple_fns
+from timeseriesflattener.utils import data_loaders
 
 msg = Printer(timestamp=True)
 
 
 @cache
 def load_df_with_cache(
-    loader_fn: Callable, kwargs: dict[str, Any], feature_name: str
+    loader_fn: Callable,
+    kwargs: dict[str, Any],
+    feature_name: str,
 ) -> pd.DataFrame:
+    """Wrapper function to cache dataframe loading."""
     msg.info(f"{feature_name}: Loading values")
     df = loader_fn(**kwargs)
     msg.good(f"{feature_name}: Loaded values")
@@ -36,11 +37,14 @@ def in_dict_and_not_none(d: dict, key: str) -> bool:
 
 
 def resolve_values_df(data: dict[str, Any]):
+    """Resolve the values_df attribute of a feature spec to a values
+    dataframe."""
     if "values_loader" not in data and "values_df" not in data:
         raise ValueError("Either values_loader or df must be specified.")
 
     if in_dict_and_not_none(d=data, key="values_loader") and in_dict_and_not_none(
-        key="values_df", d=data
+        key="values_df",
+        d=data,
     ):
         raise ValueError("Only one of values_loader or df can be specified.")
 
@@ -50,7 +54,7 @@ def resolve_values_df(data: dict[str, Any]):
             data["values_loader"] = data_loaders.get(data["values_loader"])
 
         if callable(data["values_loader"]):
-            if not "loader_kwargs" in data:
+            if "loader_kwargs" not in data:
                 data["loader_kwargs"] = {}
 
             data["values_df"] = load_df_with_cache(
@@ -103,7 +107,7 @@ class AnySpec(BaseModel):
     output_col_name_override: Optional[str] = None
     # Override the generated col name after flattening the time series.
 
-    def __init__(self, **data):
+    def __init__(self, **data: Any):
         data = resolve_values_df(data)
 
         if in_dict_and_not_none(d=data, key="output_col_name_override"):
@@ -115,12 +119,21 @@ class AnySpec(BaseModel):
         # type hint so that mypy doesn't complain.
         self.values_df: pd.DataFrame = self.values_df
 
+    def get_col_str(self) -> str:
+        """Create column name for the output column."""
+        col_str = f"{self.prefix}_{self.feature_name}"
+
+        return col_str
+
     def __eq__(self, other):
-        """Trying to run `spec in list_of_specs` works for all attributes except for df,
-        since the truth value of a dataframe is ambiguous. To remedy this, we use pandas'
+        """Trying to run `spec in list_of_specs` works for all attributes
+        except for df, since the truth value of a dataframe is ambiguous. To
+        remedy this, we use pandas'.
+
         .equals() method for comparing the dfs, and get the combined truth value.
 
-        We need to override the __eq__ method."""
+        We need to override the __eq__ method.
+        """
         other_attributes_equal = all(
             getattr(self, attr) == getattr(other, attr)
             for attr in self.__dict__
@@ -131,20 +144,14 @@ class AnySpec(BaseModel):
 
         return other_attributes_equal and dfs_equal
 
-    def get_col_str(self) -> str:
-        """Create column name for the output column."""
-        col_str = f"{self.prefix}_{self.feature_name}"
-
-        return col_str
-
 
 class StaticSpec(AnySpec):
     """Specification for a static feature."""
 
 
 class TemporalSpec(AnySpec):
-    """The minimum specification required for all collapsed time series (temporal features),
-    whether looking ahead or behind.
+    """The minimum specification required for all collapsed time series
+    (temporal features), whether looking ahead or behind.
 
     Mostly used for inheritance below.
     """
@@ -236,7 +243,10 @@ class OutcomeSpec(TemporalSpec):
 
 class MinGroupSpec(BaseModel):
     """Minimum specification for a group of features, whether they're looking
-    ahead or behind. Used to generate combinations of features."""
+    ahead or behind.
+
+    Used to generate combinations of features.
+    """
 
     values_loader: list[str]
     # Loader for the df. Tries to resolve from the resolve_multiple_nfs registry,
@@ -271,15 +281,16 @@ class MinGroupSpec(BaseModel):
 
         # Check that all passed loaders are valid
         invalid_loaders = list(
-            set(self.values_loader) - set(data_loaders.get_all().keys())
+            set(self.values_loader) - set(data_loaders.get_all().keys()),
         )
         if len(invalid_loaders) != 0:
-            nl = "\n"  # New line variable as f-string can't handle backslashes
+            # New line variable as f-string can't handle backslashes
+            nl = "\n"  # pylint: disable = invalid-name
             raise ValueError(
-                f"""Some loader strings could not be resolved in the data_loaders catalogue. Did you make a typo? If you want to add your own loaders to the catalogue, see explosion / catalogue on GitHub for info. 
+                f"""Some loader strings could not be resolved in the data_loaders catalogue. Did you make a typo? If you want to add your own loaders to the catalogue, see explosion / catalogue on GitHub for info.
                 {nl*2}Loaders that could not be resolved:"""
                 f"""{nl}{nl.join(str(loader) for loader in invalid_loaders)}{nl}{nl}"""
-                f"""Available loaders:{nl}{nl.join(str(loader) for loader in data_loaders.get_all().keys())}"""
+                f"""Available loaders:{nl}{nl.join(str(loader) for loader in data_loaders.get_all().keys())}""",
             )
 
         if self.output_col_name_override:
@@ -314,7 +325,7 @@ def create_feature_combinations_from_dict(
 
     # Create all combinations of top level elements
     permutations_dicts = [dict(zip(keys, v)) for v in itertools.product(*values)]
-    
+
     return permutations_dicts
 
 
@@ -340,6 +351,7 @@ class PredictorGroupSpec(MinGroupSpec):
     prefix = "pred"
 
     def create_combinations(self):
+        """Create all combinations from the group spec."""
         return create_specs_from_group(
             feature_group_spec=self,
             output_class=PredictorSpec,
@@ -358,6 +370,7 @@ class OutcomeGroupSpec(MinGroupSpec):
     # way during resolution, which is faster than non-incident outcomes.
 
     def create_combinations(self):
+        """Create all combinations from the group spec."""
         return create_specs_from_group(
             feature_group_spec=self,
             output_class=OutcomeSpec,
diff --git a/src/timeseriesflattener/featurizers/__init__.py b/src/timeseriesflattener/featurizers/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/timeseriesflattener/featurizers/tfidf.py b/src/timeseriesflattener/featurizers/tfidf.py
deleted file mode 100644
index 4fb7313..0000000
--- a/src/timeseriesflattener/featurizers/tfidf.py
+++ /dev/null
@@ -1,97 +0,0 @@
-"""Train a TF-IDF featurizer on train set of all clinical notes."""
-from pathlib import Path
-
-import dill as pkl
-import pandas as pd
-from sklearn.feature_extraction.text import TfidfVectorizer
-from wasabi import Printer
-
-from psycop_feature_generation.loaders.raw.load_ids import load_ids
-from psycop_feature_generation.loaders.raw.load_text import load_all_notes
-from psycop_feature_generation.utils import FEATURIZERS_PATH, PROJECT_ROOT
-
-
-def create_tfidf_vectorizer(
-    ngram_range: tuple[int, int] = (1, 2),
-    max_df: float = 0.95,
-    min_df: float = 0.01,
-    max_features: int = 100,
-) -> TfidfVectorizer:
-    """Creates a TF-IDF vectorizer with a whitespace tokenizer.
-
-    Args:
-        ngram_range (Tuple[int, int], optional): How many ngrams to make. Defaults to (1, 2).
-        max_df (float, optional): Removes words occuring in max_df proportion of documents.
-            Defaults to 0.95.
-        min_df (float, optional): Removes words occuring in less than min_df proportion
-            of documents. Defaults to 0.01.
-        max_features (int, optional): How many features to create. Defaults to 100.
-
-    Returns:
-        TfidfVectorizer: Sklearn TF-IDF vectorizer
-    """
-    return TfidfVectorizer(
-        ngram_range=ngram_range,
-        tokenizer=lambda x: x.split(" "),
-        lowercase=True,
-        max_df=max_df,  # remove very common words
-        min_df=min_df,  # remove very rare words
-        max_features=max_features,
-    )
-
-
-if __name__ == "__main__":
-
-    SYNTHETIC = False
-    OVERTACI = True
-
-    msg = Printer(timestamp=True)
-
-    # Train TF-IDF model on all notes
-    if OVERTACI:
-        if not FEATURIZERS_PATH.exists():
-            FEATURIZERS_PATH.mkdir()
-
-        text = load_all_notes(  # pylint: disable=undefined-variable
-            featurizer=None,
-            n_rows=None,
-            featurizer_kwargs=None,
-        )
-
-        # Subset only train set
-        train_ids = load_ids(split="train")
-        train_ids = train_ids["dw_ek_borger"].unique()
-        text = text[text["dw_ek_borger"].isin(train_ids)]
-        text = text["text"].tolist()
-
-        for n_features in [100, 500, 1000]:
-            msg.info(f"Fitting tf-idf with {n_features} features..")
-            vectorizer = create_tfidf_vectorizer(max_features=n_features)
-            vectorizer.fit(text)
-
-            with open(FEATURIZERS_PATH / f"tfidf_{n_features}.pkl", "wb") as f:
-                pkl.dump(vectorizer, f)
-
-            vocab = ["tfidf-" + word for word in vectorizer.get_feature_names()]
-            with open(  # type: ignore # pylint: disable=unspecified-encoding
-                FEATURIZERS_PATH / f"tfidf_{n_features}_vocab.txt",
-                "w",
-            ) as f:
-                f.write("\n".join(vocab))  # type: ignore
-
-    # train TF-IDF on synthetic data
-    if SYNTHETIC:
-        test_path = PROJECT_ROOT / "tests" / "test_data"
-        save_dir = test_path / "test_tfidf"
-        if not save_dir.exists():
-            save_dir.mkdir()
-
-        text = pd.read_csv(test_path / "synth_txt_data.csv")
-        text = text["text"].dropna().tolist()
-
-        msg.info("Fitting tf-idf with 10 features..")
-        vectorizer = create_tfidf_vectorizer(max_features=10)
-        vectorizer.fit(text)
-
-        with open(save_dir / "tfidf_10.pkl", "wb") as f:
-            pkl.dump(vectorizer, f)
diff --git a/src/timeseriesflattener/timeseriesflattener/flattened_dataset.py b/src/timeseriesflattener/flattened_dataset.py
similarity index 97%
rename from src/timeseriesflattener/timeseriesflattener/flattened_dataset.py
rename to src/timeseriesflattener/flattened_dataset.py
index 9bb095a..165a39e 100644
--- a/src/timeseriesflattener/timeseriesflattener/flattened_dataset.py
+++ b/src/timeseriesflattener/flattened_dataset.py
@@ -8,7 +8,7 @@ from collections.abc import Callable
 from datetime import timedelta
 from multiprocessing import Pool
 from pathlib import Path
-from typing import Any, Optional, Union
+from typing import Any, Optional
 
 import numpy as np
 import pandas as pd
@@ -18,26 +18,22 @@ from dask.diagnostics import ProgressBar
 from pandas import DataFrame
 from wasabi import Printer, msg
 
-from psycop_feature_generation.timeseriesflattener.feature_spec_objects import (
+from timeseriesflattener.feature_spec_objects import (
     AnySpec,
     OutcomeSpec,
     PredictorSpec,
     TemporalSpec,
 )
-from psycop_feature_generation.timeseriesflattener.flattened_ds_validator import (
-    ValidateInitFlattenedDataset,
-)
-from psycop_feature_generation.timeseriesflattener.resolve_multiple_functions import (
-    resolve_multiple_fns,
-)
-from psycop_feature_generation.utils import load_dataset_from_file, write_df_to_file
+from timeseriesflattener.flattened_ds_validator import ValidateInitFlattenedDataset
+from timeseriesflattener.resolve_multiple_functions import resolve_multiple_fns
+from timeseriesflattener.utils import load_dataset_from_file, write_df_to_file
 
 ProgressBar().register()
 
 
 class FlattenedDataset:  # pylint: disable=too-many-instance-attributes
     """Turn a set of time-series into tabular prediction-time data.
-    
+
     Attributes:
         df (DataFrame): Dataframe with prediction times, required cols: patient_id, .
         n_workers (int): Number of subprocesses to spawn for parallelization.
@@ -225,7 +221,7 @@ class FlattenedDataset:  # pylint: disable=too-many-instance-attributes
             DataFrame
         """
         for col_name in (timestamp_col_name, id_col_name):
-            if col_name not in output_spec.values_df.columns:
+            if col_name not in output_spec.values_df.columns:  # type: ignore
                 raise ValueError(
                     f"{col_name} does not exist in df_prediction_times, change the df or set another argument",
                 )
@@ -327,7 +323,7 @@ class FlattenedDataset:  # pylint: disable=too-many-instance-attributes
 
             # Fallback values are not interesting for cache hit. If they exist in generated_df, they should be dropped
             # in the cache. Saves on storage. Don't use them to check if cache is hit.
-            if not np.isnan(output_spec.fallback):
+            if not np.isnan(output_spec.fallback):  # type: ignore
                 generated_df = generated_df[
                     generated_df[value_col_str] != output_spec.fallback
                 ]
@@ -342,7 +338,7 @@ class FlattenedDataset:  # pylint: disable=too-many-instance-attributes
 
     def _cache_is_hit(
         self,
-        output_spec: Union[PredictorSpec, PredictorSpec],
+        output_spec: TemporalSpec,
         file_pattern: str,
         file_suffix: str,
     ) -> bool:
@@ -421,7 +417,7 @@ class FlattenedDataset:  # pylint: disable=too-many-instance-attributes
     def _write_feature_to_cache(
         self,
         values_df: pd.DataFrame,
-        predictor_spec: PredictorSpec,
+        predictor_spec: TemporalSpec,
         file_name: str,
     ):
         """Write feature to cache."""
@@ -441,9 +437,9 @@ class FlattenedDataset:  # pylint: disable=too-many-instance-attributes
             file_path=self.feature_cache_dir / f"{file_name}_{timestamp}.parquet",
         )
 
-    def _get_feature(
+    def _get_temporal_feature(
         self,
-        feature_spec: AnySpec,
+        feature_spec: TemporalSpec,
         file_suffix: str = "parquet",
     ) -> pd.DataFrame:
         """Get feature. Either load from cache, or generate if necessary.
@@ -571,7 +567,7 @@ class FlattenedDataset:  # pylint: disable=too-many-instance-attributes
         with Pool(self.n_workers) as p:
             flattened_predictor_dfs = list(
                 tqdm.tqdm(
-                    p.imap(func=self._get_feature, iterable=predictor_specs),
+                    p.imap(func=self._get_temporal_feature, iterable=predictor_specs),
                     total=len(predictor_specs),
                 ),
             )
@@ -589,7 +585,8 @@ class FlattenedDataset:  # pylint: disable=too-many-instance-attributes
         output_prefix: str = "pred",
         birth_year_as_predictor: bool = False,
     ):
-        """Add age at prediction time and patient's birth year to each prediction time.
+        """Add age at prediction time and patient's birth year to each
+        prediction time.
 
         Args:
             id2date_of_birth (DataFrame): Two columns, id and date_of_birth.
@@ -650,7 +647,7 @@ class FlattenedDataset:  # pylint: disable=too-many-instance-attributes
         if static_spec.input_col_name_override is None:
             possible_value_cols = [
                 col
-                for col in static_spec.values_df.columns
+                for col in static_spec.values_df.columns  # type: ignore
                 if col not in self.id_col_name
             ]
 
@@ -674,8 +671,8 @@ class FlattenedDataset:  # pylint: disable=too-many-instance-attributes
 
         df = pd.DataFrame(
             {
-                self.id_col_name: static_spec.values_df[self.id_col_name],
-                output_col_name: static_spec.values_df[value_col_name],
+                self.id_col_name: static_spec.values_df[self.id_col_name],  # type: ignore
+                output_col_name: static_spec.values_df[value_col_name],  # type: ignore
             },
         )
 
@@ -776,7 +773,7 @@ class FlattenedDataset:  # pylint: disable=too-many-instance-attributes
         Args:
             output_spec (Union[OutcomeSpec, PredictorSpec]): Specification of the output column.
         """
-        timestamp_col_type = output_spec.values_df[self.timestamp_col_name].dtype
+        timestamp_col_type = output_spec.values_df[self.timestamp_col_name].dtype  # type: ignore
 
         if timestamp_col_type not in ("Timestamp", "datetime64[ns]"):
             # Convert dtype to timestamp
diff --git a/src/timeseriesflattener/timeseriesflattener/flattened_ds_cache.py b/src/timeseriesflattener/flattened_ds_cache.py
similarity index 100%
rename from src/timeseriesflattener/timeseriesflattener/flattened_ds_cache.py
rename to src/timeseriesflattener/flattened_ds_cache.py
diff --git a/src/timeseriesflattener/timeseriesflattener/flattened_ds_validator.py b/src/timeseriesflattener/flattened_ds_validator.py
similarity index 91%
rename from src/timeseriesflattener/timeseriesflattener/flattened_ds_validator.py
rename to src/timeseriesflattener/flattened_ds_validator.py
index 49c26e9..0320d33 100644
--- a/src/timeseriesflattener/timeseriesflattener/flattened_ds_validator.py
+++ b/src/timeseriesflattener/flattened_ds_validator.py
@@ -1,9 +1,17 @@
+"""Validator for a flattened dataset."""
 import pandas as pd
 
-from psycop_feature_generation.utils import df_contains_duplicates
+from timeseriesflattener.utils import df_contains_duplicates
 
 
 class ValidateInitFlattenedDataset:
+    """Validator for a flattened dataset."""
+
+    def __init__(self, df: pd.DataFrame, timestamp_col_name: str, id_col_name: str):
+        self.df = df
+        self.timestamp_col_name = timestamp_col_name
+        self.id_col_name = id_col_name
+
     def _check_timestamp_col_type(self):
         """Check that the timestamp column is of type datetime."""
         timestamp_col_type = type(self.df[self.timestamp_col_name][0]).__name__
@@ -38,12 +46,8 @@ class ValidateInitFlattenedDataset:
                     f"{col_name} does not exist in prediction_times_df, change the df or set another argument",
                 )
 
-    def __init__(self, df: pd.DataFrame, timestamp_col_name: str, id_col_name: str):
-        self.df = df
-        self.timestamp_col_name = timestamp_col_name
-        self.id_col_name = id_col_name
-
     def validate_dataset(self):
+        """Validate the entire dataset."""
         self._check_that_timestamp_and_id_columns_exist()
         self._check_for_duplicate_rows()
         self._check_timestamp_col_type()
diff --git a/src/timeseriesflattener/loaders/__init__.py b/src/timeseriesflattener/loaders/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/timeseriesflattener/loaders/non_numerical_coercer.py b/src/timeseriesflattener/loaders/non_numerical_coercer.py
deleted file mode 100644
index f636191..0000000
--- a/src/timeseriesflattener/loaders/non_numerical_coercer.py
+++ /dev/null
@@ -1,64 +0,0 @@
-"""Some of our data series contain both numerical values and strings like
-'>=12'.
-
-This function takes a df and coerces all strings into numerical.
-"""
-
-from typing import Optional
-
-import pandas as pd
-
-
-def multiply_inequalities_in_df(
-    df: pd.DataFrame,
-    round_to_decimals: int = 6,
-    ineq2mult: Optional[dict[str, float]] = None,
-    col_to_multiply: str = "value",
-) -> pd.DataFrame:
-    """Multiply inequalities in a dataframe by a factor.
-
-    Args:
-        df (pd.Dataframe): The dataframe to be modified.
-        round_to_decimals (int): How many decimals to round the value to.
-        ineq2mult (dict[str, float]): A dictionary with the inequalities as keys and the factors as values.
-            Current values are arbitrary, but ensure that inequalities are somewhat separated from the continuous part of the distribution.
-        col_to_multiply (str): The column to multiply.
-
-    Returns:
-        pd.Dataframe: The modified dataframe.
-    """
-    if (
-        ineq2mult is None
-    ):  # Avoid sharing a mutable keyword argument between function invocations
-        ineq2mult = {
-            "<": 0.67,
-            "<=": 0.8,
-            ">": 1.5,
-            ">=": 1.2,
-        }
-
-    # Sort inequalities by length, so that we don't replace "<" in "<=".
-    in_eqs = sorted(ineq2mult.keys(), key=len, reverse=True)
-
-    for in_eq in in_eqs:
-        try:
-            starts_with_ineq_idxs = (
-                df[col_to_multiply].str.startswith(in_eq).fillna(False)
-            )
-        except AttributeError:
-            # If the column is no longer a string (i.e. all values have been coerced), continue
-            continue
-
-        df.loc[starts_with_ineq_idxs, col_to_multiply] = (
-            df.loc[starts_with_ineq_idxs, col_to_multiply]
-            .str.replace(",", ".")
-            .str.extract(r"(\d+\.\d+|\d+)", expand=False)
-            .astype(float)
-            .mul(ineq2mult[in_eq])
-            .round(round_to_decimals)
-        )
-
-    # Convert col_to_multiply dtype to float
-    df[col_to_multiply] = df[col_to_multiply].astype(float)
-
-    return df
diff --git a/src/timeseriesflattener/loaders/raw/__init__.py b/src/timeseriesflattener/loaders/raw/__init__.py
deleted file mode 100644
index 36b3498..0000000
--- a/src/timeseriesflattener/loaders/raw/__init__.py
+++ /dev/null
@@ -1,17 +0,0 @@
-"""Import all raw loaders."""
-
-from ...data_checks.raw.check_predictor_lists import (  # noqa
-    check_feature_combinations_return_correct_dfs,
-)
-from .load_admissions import *  # noqa
-from .load_coercion import *  # noqa
-from .load_demographic import *  # noqa
-from .load_diagnoses import *  # noqa
-from .load_ids import *  # noqa
-from .load_lab_results import *  # noqa
-from .load_medications import *  # noqa
-from .load_structured_sfi import *  # noqa
-from .load_t2d_outcomes import *  # noqa
-from .load_visits import *  # noqa
-from .sql_load import *  # noqa
-from .t2d_loaders import *  # noqa
diff --git a/src/timeseriesflattener/loaders/raw/load_admissions.py b/src/timeseriesflattener/loaders/raw/load_admissions.py
deleted file mode 100644
index a95f7d5..0000000
--- a/src/timeseriesflattener/loaders/raw/load_admissions.py
+++ /dev/null
@@ -1,94 +0,0 @@
-"""Load admissions."""
-from typing import Optional
-
-import pandas as pd
-from wasabi import msg
-
-from psycop_feature_generation.loaders.raw.sql_load import sql_load
-from psycop_feature_generation.utils import data_loaders
-
-
-@data_loaders.register("admissions")
-def admissions(
-    shak_code: Optional[int] = None,
-    shak_sql_operator: Optional[str] = "=",
-    n_rows: Optional[int] = None,
-) -> pd.DataFrame:
-    """Load admissions. Outputs a value column containing length of admission
-    in days.
-
-    Args:
-        shak_code (Optional[int], optional): SHAK code indicating where to keep/not keep visits from (e.g. 6600). Combines with
-            shak_sql_operator, e.g. "!= 6600". Defaults to None, in which case all admissions are kept.
-        shak_sql_operator (Optional[str], optional): Operator to use with shak_code. Defaults to "=".
-        n_rows (Optional[int], optional): Number of rows to return. Defaults to None.
-
-    Returns:
-        pd.DataFrame: Dataframe with all physical visits to psychiatry. Has columns dw_ek_borger, timestamp and value (length of admissions in days).
-    """
-
-    # SHAK = 6600 ≈ in psychiatry
-    d = {
-        "LPR3": {
-            "view": "[FOR_LPR3kontakter_psyk_somatik_inkl_2021_feb2022]",
-            "datetime_col": "datotid_lpr3kontaktstart",
-            "value_col": "datotid_lpr3kontaktslut",
-            "location_col": "shakkode_lpr3kontaktansvarlig",
-            "where": "AND pt_type = 'Indlæggelse'",
-        },
-        "LPR2_admissions": {
-            "view": "[FOR_indlaeggelser_psyk_somatik_LPR2_inkl_2021_feb2022]",
-            "datetime_col": "datotid_indlaeggelse",
-            "value_col": "datotid_udskrivning",
-            "location_col": "shakKode_kontaktansvarlig",
-            "where": "",
-        },
-    }
-
-    dfs = []
-
-    for meta in d.values():
-        cols = f"{meta['datetime_col']}, {meta['value_col']}, dw_ek_borger"
-
-        sql = f"SELECT {cols} FROM [fct].{meta['view']} WHERE {meta['datetime_col']} IS NOT NULL AND {meta['value_col']} IS NOT NULL {meta['where']}"
-
-        if shak_code is not None:
-            sql += f" AND left({meta['location_col']}, {len(str(shak_code))}) {shak_sql_operator} {str(shak_code)}"
-
-        df = sql_load(sql, database="USR_PS_FORSK", chunksize=None, n_rows=n_rows)
-        df.rename(
-            columns={meta["datetime_col"]: "timestamp", meta["value_col"]: "value"},
-            inplace=True,
-        )
-
-        dfs.append(df)
-
-    # Concat the list of dfs
-    output_df = pd.concat(dfs)
-
-    # 0,8% of visits are duplicates. Unsure if overlap between sources or errors in source data. Removing.
-    output_df = output_df.drop_duplicates(
-        subset=["timestamp", "dw_ek_borger"],
-        keep="first",
-    )
-
-    # Change value column to length of admission in days
-    output_df["value"] = (
-        output_df["value"] - output_df["timestamp"]
-    ).dt.total_seconds() / 86400
-
-    msg.good("Loaded admissions data")
-
-    return output_df.reset_index(drop=True)
-
-
-@data_loaders.register("admissions_to_psychiatry")
-def admissions_to_psychiatry(n_rows: Optional[int] = None) -> pd.DataFrame:
-    """Load admissions to psychiatry."""
-    return admissions(shak_code=6600, shak_sql_operator="=", n_rows=n_rows)
-
-
-@data_loaders.register("admissions_to_somatic")
-def admissions_to_somatic(n_rows: Optional[int] = None) -> pd.DataFrame:
-    """Load admissions to somatic."""
-    return admissions(shak_code=6600, shak_sql_operator="!=", n_rows=n_rows)
diff --git a/src/timeseriesflattener/loaders/raw/load_coercion.py b/src/timeseriesflattener/loaders/raw/load_coercion.py
deleted file mode 100644
index 3615b66..0000000
--- a/src/timeseriesflattener/loaders/raw/load_coercion.py
+++ /dev/null
@@ -1,325 +0,0 @@
-"""Loaders for coercion data."""
-
-# pylint: disable = non-ascii-name,missing-function-docstring
-
-from typing import Optional
-
-import pandas as pd
-
-from psycop_feature_generation.loaders.raw.sql_load import sql_load
-from psycop_feature_generation.utils import data_loaders
-
-
-@data_loaders.register("coercion_duration")
-def coercion_duration(
-    coercion_type: Optional[str] = None,
-    reason_for_coercion: Optional[str] = None,
-    n_rows: Optional[int] = None,
-) -> pd.DataFrame:
-    """Load coercion data. By default returns entire coercion data view with
-    duration in hours as the value column.
-
-    Args:
-        coercion_type (str): Type of coercion, e.g. 'tvangsindlæggelse', 'bæltefiksering'. Defaults to None. # noqa: DAR102
-        reason_for_coercion (str): Reason for coercion, e.g. 'farlighed'. Defaults to None.
-        n_rows: Number of rows to return. Defaults to None which returns entire coercion data view.
-
-    Returns:
-        pd.DataFrame
-    """
-    coercion_discard = """('Døraflåsning', 'Personlig afskærmning over 24 timer', 'Koordinationsplan',
-    'Udskrivningsaftale', 'Særlige dørlåse', 'Personlige alarm- og pejlesystemer', 'Andet' )"""
-
-    view = "[FOR_tvang_alt_hele_kohorten_inkl_2021]"
-
-    sql = f"SELECT dw_ek_borger, datotid_start_sei, varighed_timer_sei, typetekst_sei FROM [fct].{view} WHERE datotid_start_sei IS NOT NULL AND typetekst_sei NOT IN {coercion_discard}"
-
-    if coercion_type and reason_for_coercion is None:
-
-        sql += f" AND typetekst_sei = '{coercion_type}'"
-
-    if coercion_type is None and reason_for_coercion:
-
-        sql += f" AND begrundtekst_sei = '{reason_for_coercion}'"
-
-    if coercion_type and reason_for_coercion:
-
-        sql += f" AND typetekst_sei = '{coercion_type}' AND begrundtekst_sei = '{reason_for_coercion}'"
-
-    df = sql_load(sql, database="USR_PS_FORSK", chunksize=None, n_rows=n_rows)
-
-    # Drop duplicate rows
-    df = df.drop_duplicates(keep="first")
-
-    df.rename(
-        columns={"datotid_start_sei": "timestamp", "varighed_timer_sei": "value"},
-        inplace=True,
-    )
-
-    # Change NaNs to 0
-    df["value"].fillna(0, inplace=True)
-
-    return df.reset_index(drop=True)
-
-
-def _concatenate_coercion(
-    coercion_types_list: list[dict[str, str]],
-    n_rows: Optional[int] = None,
-) -> pd.DataFrame:
-    """Aggregate multiple types of coercion with multiple reasons into one
-    column.
-
-    Args:
-        coercion_types_list (list): list of dictionaries containing a 'coercion_type' key and a 'reason_for_coercion' key. If keys not in dicts, they are set to None # noqa: DAR102
-        n (int, optional): Number of rows to return. Defaults to None.
-
-    Returns:
-        pd.DataFrame
-    """
-
-    for d in coercion_types_list:  # Make sure proper keys are given
-        if "coercion_type" not in d and "reason_for_coercion" not in d:
-            raise KeyError(
-                f'{d} does not contain either "coercion_type"  or "reason_for_coercion". At least one is required.',
-            )
-        if "coercion_type" not in d:
-            d["coercion_type"] = None  # type: ignore
-        if "reason_for_coercion" not in d:
-            d["reason_for_coercion"] = None  # type: ignore
-
-    dfs = [
-        coercion_duration(
-            coercion_type=d["coercion_type"],
-            reason_for_coercion=d["reason_for_coercion"],
-            n_rows=n_rows,
-        )
-        for d in coercion_types_list
-    ]
-
-    return pd.concat(dfs, axis=0).reset_index(drop=True)
-
-
-# REASON (begrundtekst_sei) #
-
-
-@data_loaders.register("farlighed")
-def farlighed(n_rows: Optional[int] = None) -> pd.DataFrame:
-    coercion_types_list = [
-        {
-            "reason_for_coercion": "Farlighed",
-        },
-        {
-            "reason_for_coercion": "På grund af farlighed",
-        },
-    ]
-
-    return _concatenate_coercion(
-        coercion_types_list=coercion_types_list,
-        n_rows=n_rows,
-    )
-
-
-# Røde papir ved tvangsindlæggelse/tvangstilbageholdelse
-@data_loaders.register("paa_grund_af_farlighed")
-def paa_grund_af_farlighed(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return coercion_duration(
-        reason_for_coercion="På grund af farlighed",
-        n_rows=n_rows,
-    )
-
-
-# Gule papir ved tvangsindlæggelse/tvangstilbageholdelse
-@data_loaders.register("af_helbredsmaessige_grunde")
-def af_helbredsmaessige_grunde(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return coercion_duration(
-        reason_for_coercion=" Af helbredsmæssige grunde",
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("urolig_tilstand")
-def urolig_tilstand(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return coercion_duration(
-        reason_for_coercion="Urolig tilstand",
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("anden_begrundelse")
-def anden_begrundelse(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return coercion_duration(
-        reason_for_coercion="Anden begrundelse",
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("naerliggende_eller_vaesentlig_fare_for_patienten_eller_andre")
-def naerliggende_fare(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return coercion_duration(
-        reason_for_coercion="Nærliggende_eller_væsentlig_fare_for_patienten_eller_andre",
-        n_rows=n_rows,
-    )
-
-
-# GENERAL TYPE (tabeltekst) ###
-# frihedsberøvelser
-@data_loaders.register("skema_1")
-def skema_1(n_rows: Optional[int] = None) -> pd.DataFrame:
-    coercion_types_list = [
-        {
-            "coercion_type": "Tvangsindlæggelse",
-        },
-        {
-            "coercion_type": "Tvangstilbageholdelse",
-        },
-    ]
-
-    return _concatenate_coercion(
-        coercion_types_list=coercion_types_list,
-        n_rows=n_rows,
-    )
-
-
-# tvangsbehandlinger
-@data_loaders.register("skema_2")
-def skema_2(n_rows: Optional[int] = None) -> pd.DataFrame:
-    coercion_types_list = [
-        {
-            "coercion_type": "Af legemlig lidelse",
-        },
-        {
-            "coercion_type": "Medicinering",
-        },
-        {
-            "coercion_type": "Ernæring",
-        },
-        {
-            "coercion_type": "ECT",
-        },
-    ]
-
-    return _concatenate_coercion(
-        coercion_types_list=coercion_types_list,
-        n_rows=n_rows,
-    )
-
-
-# magtanvendelse
-@data_loaders.register("skema_3")
-def skema_3(n_rows: Optional[int] = None) -> pd.DataFrame:
-    coercion_types_list = [
-        {
-            "coercion_type": "Bælte",
-        },
-        {
-            "coercion_type": "Remme",
-        },
-        {
-            "coercion_type": "Fastholden",
-        },
-        {
-            "coercion_type": "Beroligende medicin",
-        },
-        {
-            "coercion_type": "Handsker",
-        },
-    ]
-
-    # "døraflåsning" and "personlig skærmning" are not included
-
-    return _concatenate_coercion(
-        coercion_types_list=coercion_types_list,
-        n_rows=n_rows,
-    )
-
-
-# SPECIFIC TYPE (typetekst_sei) ###
-# exists in the data, but not included here: [døraflåsning, personlig afskærmning, stofbælte, særlige dørlåse, tvungen opfølgning, personlige alarm, udskrivningsaftale, koordinationsplan]
-
-
-@data_loaders.register("baelte")
-def baelte(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return coercion_duration(
-        coercion_type="Bælte",
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("remme")
-def remme(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return coercion_duration(
-        coercion_type="Remme",
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("fastholden")
-def fastholden(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return coercion_duration(
-        coercion_type="Fastholden",
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("beroligende_medicin")
-def beroligende_medicin(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return coercion_duration(
-        coercion_type="Beroligende medicin",
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("handsker")
-def handsker(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return coercion_duration(
-        coercion_type="Handsker",
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("tvangsindlaeggelse")
-def tvangsindlaeggelse(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return coercion_duration(
-        coercion_type="Tvangsindlæggelse",
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("tvangstilbageholdelse")
-def tvangstilbageholdelse(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return coercion_duration(
-        coercion_type="Tvangstilbageholdelse",
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("medicinering")
-def medicinering(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return coercion_duration(
-        coercion_type="Medicinering",
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("ect")
-def ect(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return coercion_duration(
-        coercion_type="ECT",
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("ernaering")
-def ernaering(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return coercion_duration(
-        coercion_type="Ernæring",
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("af_legemlig_lidelse")
-def af_legemlig_lidelse(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return coercion_duration(
-        coercion_type="Af legemlig lidelse",
-        n_rows=n_rows,
-    )
diff --git a/src/timeseriesflattener/loaders/raw/load_demographic.py b/src/timeseriesflattener/loaders/raw/load_demographic.py
deleted file mode 100644
index 06b2331..0000000
--- a/src/timeseriesflattener/loaders/raw/load_demographic.py
+++ /dev/null
@@ -1,47 +0,0 @@
-"""Loaders for demographic information."""
-
-from typing import Optional
-
-import pandas as pd
-
-from psycop_feature_generation.loaders.raw.sql_load import sql_load
-from psycop_feature_generation.utils import data_loaders
-
-# pylint: disable=missing-function-docstring
-
-
-@data_loaders.register("birthdays")  # noqa
-def birthdays(n_rows: Optional[int] = None) -> pd.DataFrame:
-    view = "[FOR_kohorte_demografi_inkl_2021_feb2022]"
-
-    sql = f"SELECT dw_ek_borger, foedselsdato FROM [fct].{view}"
-
-    df = sql_load(sql, database="USR_PS_FORSK", chunksize=None, n_rows=n_rows)
-
-    # Typically handled by sql_load, but because foedselsdato doesn't contain "datotid" in its name,
-    # We must handle it manually here
-    df["foedselsdato"] = pd.to_datetime(df["foedselsdato"], format="%Y-%m-%d")
-
-    df.rename(columns={"foedselsdato": "date_of_birth"}, inplace=True)
-
-    # msg.good("Loaded birthdays")
-    return df.reset_index(drop=True)
-
-
-@data_loaders.register("sex_female")
-def sex_female(n_rows: Optional[int] = None) -> pd.DataFrame:
-    view = "[FOR_kohorte_demografi_inkl_2021_feb2022]"
-
-    sql = f"SELECT dw_ek_borger, koennavn FROM [fct].{view}"
-
-    df = sql_load(sql, database="USR_PS_FORSK", chunksize=None, n_rows=n_rows)
-
-    df.loc[df["koennavn"] == "Mand", "koennavn"] = False
-    df.loc[df["koennavn"] == "Kvinde", "koennavn"] = True
-
-    df.rename(
-        columns={"koennavn": "sex_female"},
-        inplace=True,
-    )
-
-    return df.reset_index(drop=True)
diff --git a/src/timeseriesflattener/loaders/raw/load_diagnoses.py b/src/timeseriesflattener/loaders/raw/load_diagnoses.py
deleted file mode 100644
index 2ed4513..0000000
--- a/src/timeseriesflattener/loaders/raw/load_diagnoses.py
+++ /dev/null
@@ -1,653 +0,0 @@
-"""Loaders for diagnosis codes.
-
-Is growing quite a bit, loaders may have to be split out into separate
-files (e.g. psychiatric, cardiovascular, metabolic etc.) over time.
-"""
-
-# pylint: disable=missing-function-docstring
-
-from typing import Optional, Union
-
-import pandas as pd
-
-from psycop_feature_generation.loaders.raw.utils import load_from_codes
-from psycop_feature_generation.utils import data_loaders
-
-
-def concat_from_physical_visits(
-    icd_codes: list[str],
-    output_col_name: str,
-    wildcard_icd_code: Optional[bool] = False,
-    n_rows: Optional[int] = None,
-) -> pd.DataFrame:
-    """Load all diagnoses matching any icd_code in icd_codes. Create
-    output_col_name and set to 1.
-
-    Args:
-        icd_codes (list[str]): list of icd_codes. # noqa: DAR102
-        output_col_name (str): Output column name
-        wildcard_icd_code (bool, optional): Whether to match on icd_codes* or icd_codes. Defaults to False.
-        n_rows: Number of rows to return. Defaults to None.
-
-    Returns:
-        pd.DataFrame
-    """
-
-    diagnoses_source_table_info = {
-        "lpr3": {
-            "view": "FOR_LPR3kontakter_psyk_somatik_inkl_2021_feb2022",
-            "source_timestamp_col_name": "datotid_lpr3kontaktstart",
-        },
-        "lpr2_inpatient": {
-            "view": "FOR_indlaeggelser_psyk_somatik_LPR2_inkl_2021_feb2022",
-            "source_timestamp_col_name": "datotid_indlaeggelse",
-        },
-        "lpr2_acute_outpatient": {
-            "view": "FOR_akutambulantekontakter_psyk_somatik_LPR2_inkl_2021_feb2022",
-            "source_timestamp_col_name": "datotid_start",
-        },
-        "lpr2_outpatient": {
-            "view": "FOR_besoeg_psyk_somatik_LPR2_inkl_2021_feb2022",
-            "source_timestamp_col_name": "datotid_start",
-        },
-    }
-
-    dfs = [
-        load_from_codes(
-            codes_to_match=icd_codes,
-            code_col_name="diagnosegruppestreng",
-            output_col_name=output_col_name,
-            match_with_wildcard=wildcard_icd_code,
-            n_rows=n_rows,
-            load_diagnoses=True,
-            **kwargs,
-        )
-        for _, kwargs in diagnoses_source_table_info.items()
-    ]
-
-    df = pd.concat(dfs).drop_duplicates(
-        subset=["dw_ek_borger", "timestamp", "value"],
-        keep="first",
-    )
-    return df.reset_index(drop=True)
-
-
-def from_physical_visits(
-    icd_code: Union[list[str], str],
-    output_col_name: Optional[str] = "value",
-    n_rows: Optional[int] = None,
-    wildcard_icd_code: Optional[bool] = False,
-) -> pd.DataFrame:
-    """Load diagnoses from all physical visits. If icd_code is a list, will
-    aggregate as one column (e.g. ["E780", "E785"] into a ypercholesterolemia
-    column).
-
-    Args:
-        icd_code (str): Substring to match diagnoses for. Matches any diagnoses, whether a-diagnosis, b-diagnosis etc. # noqa: DAR102
-        output_col_name (str, optional): Name of new column string. Defaults to "value".
-        n_rows: Number of rows to return. Defaults to None.
-        wildcard_icd_code (bool, optional): Whether to match on icd_code*. Defaults to False.
-
-    Returns:
-        pd.DataFrame
-    """
-
-    diagnoses_source_table_info = {
-        "lpr3": {
-            "view": "FOR_LPR3kontakter_psyk_somatik_inkl_2021",
-            "source_timestamp_col_name": "datotid_lpr3kontaktstart",
-        },
-        "lpr2_inpatient": {
-            "view": "FOR_indlaeggelser_psyk_somatik_LPR2_inkl_2021",
-            "source_timestamp_col_name": "datotid_indlaeggelse",
-        },
-        "lpr2_outpatient": {
-            "view": "FOR_besoeg_psyk_somatik_LPR2_inkl_2021",
-            "source_timestamp_col_name": "datotid_start",
-        },
-    }
-
-    if n_rows:
-        n_rows_per_df = int(n_rows / len(diagnoses_source_table_info))
-    else:
-        n_rows_per_df = None
-
-    dfs = [
-        load_from_codes(
-            codes_to_match=icd_code,
-            code_col_name="diagnosegruppestreng",
-            output_col_name=output_col_name,
-            n_rows=n_rows_per_df,
-            match_with_wildcard=wildcard_icd_code,
-            **kwargs,
-            load_diagnoses=True,
-        )
-        for _, kwargs in diagnoses_source_table_info.items()
-    ]
-
-    df = pd.concat(dfs).drop_duplicates(
-        subset=["dw_ek_borger", "timestamp", "value"],
-        keep="first",
-    )
-
-    return df.reset_index(drop=True)
-
-
-@data_loaders.register("essential_hypertension")
-def essential_hypertension(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="I109",
-        wildcard_icd_code=False,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("hyperlipidemia")
-def hyperlipidemia(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=[
-            "E780",
-            "E785",
-        ],  # Only these two, as the others are exceedingly rare
-        wildcard_icd_code=False,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("liverdisease_unspecified")
-def liverdisease_unspecified(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="K769",
-        wildcard_icd_code=False,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("polycystic_ovarian_syndrome")
-def polycystic_ovarian_syndrome(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="E282",
-        wildcard_icd_code=False,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("sleep_apnea")
-def sleep_apnea(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=["G473", "G4732"],
-        wildcard_icd_code=False,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("sleep_problems_unspecified")
-def sleep_problems_unspecified(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="G479",
-        wildcard_icd_code=False,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("copd")
-def copd(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=["j44"],
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-# Psychiatric diagnoses
-# data loaders for all diagnoses in the f0-chapter (organic mental disorders)
-@data_loaders.register("f0_disorders")
-def f0_disorders(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f0",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("dementia")
-def dementia(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=["f00", "f01", "f02", "f03", "f04"],
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("delirium")
-def delirium(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f05",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("miscellaneous_organic_mental_disorders")
-def misc_organic_mental_disorders(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=["f06", "f07", "f09"],
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-# data loaders for all diagnoses in the f1-chapter (mental and behavioural disorders due to psychoactive substance use)
-@data_loaders.register("f1_disorders")
-def f1_disorders(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f1",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("alcohol_dependency")
-def alcohol_dependency(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f10",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("opioid_dependency")
-def opioids_and_sedatives(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f11",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("cannabinoid_dependency")
-def cannabinoid_dependency(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f12",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("sedative_dependency")
-def sedative_dependency(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f13",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("stimulant_dependencies")
-def stimulant_deo(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=["f14", "f15"],
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("hallucinogen_dependency")
-def hallucinogen_dependency(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f16",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("tobacco_dependency")
-def tobacco_dependency(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f17",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("miscellaneous_drug_dependencies")
-def misc_drugs(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=["f18", "f19"],
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-# data loaders for all diagnoses in the f2-chapter (schizophrenia, schizotypal and delusional disorders)
-
-
-@data_loaders.register("f2_disorders")
-def f2_disorders(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f2",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("schizophrenia")
-def schizophrenia(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f20",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("schizoaffective")
-def schizoaffective(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f25",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("miscellaneous_psychotic_disorders")
-def misc_psychosis(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=["f21", "f22", "f23", "f24", "f28", "f29"],
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-# data loaders for all diagnoses in the f3-chapter (mood (affective) disorders).
-
-
-@data_loaders.register("f3_disorders")
-def f3_disorders(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f3",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("manic_and_bipolar")
-def manic_and_bipolar(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=["f30", "f31"],
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("depressive_disorders")
-def depressive_disorders(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=["f32", "f33", "f34", "f38"],
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("miscellaneous_affective_disorders")
-def misc_affective_disorders(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=["f38", "f39"],
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-# data loaders for all diagnoses in the f4-chapter (neurotic, stress-related and somatoform disorders).
-
-
-@data_loaders.register("f4_disorders")
-def f4_disorders(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f4",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("phobic_anxiety_ocd")
-def phobic_and_anxiety(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=["f40", "f41", "f42"],
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("reaction_to_severe_stress_and_adjustment_disorders")
-def stress_and_adjustment(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f43",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("dissociative_somatoform_miscellaneous")
-def dissociative_somatoform_and_misc(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=["f44", "f45", "f48"],
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-# data loaders for all diagnoses in the f5-chapter (behavioural syndromes associated with physiological disturbances and physical factors).
-
-
-@data_loaders.register("f5_disorders")
-def f5_disorders(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f5",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("eating_disorders")
-def eating_disorders(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f50",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("sleeping_and_sexual_disorders")
-def sleeping_and_sexual_disorders(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=["f51", "f52"],
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("miscellaneous_f5_disorders")
-def misc_f5(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=["f53", "f54", "f55", "f59"],
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-# data loaders for all diagnoses in the f6-chapter (disorders of adult personality and behaviour).
-@data_loaders.register("f6_disorders")
-def f6_disorders(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f6",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("cluster_a")
-def cluster_a(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=["f600", "f601"],
-        wildcard_icd_code=False,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("cluster_b")
-def cluster_b(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=["f602", "f603", "f604"],
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("cluster_c")
-def cluster_c(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=["f605", "f606", "f607"],
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("miscellaneous_personality_disorders")
-def misc_personality_disorders(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=["f608", "f609", "f61", "f62", "f63", "f68", "f69"],
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("sexual_disorders")
-def misc_personality(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=["f65", "f66"],
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-    # f64 sexual identity disorders is excluded
-
-
-# data loaders for all diagnoses in the f7-chapter (mental retardation).
-@data_loaders.register("f7_disorders")
-def f7_disorders(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f7",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("mild_mental_retardation")
-def mild_mental_retardation(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f70",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("moderate_mental_retardation")
-def moderate_mental_retardation(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f71",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("severe_mental_retardation")
-def severe_mental_retardation(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=["f72", "f73"],
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("miscellaneous_mental_retardation_disorders")
-def misc_mental_retardation(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=["f78", "f79"],
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-# data loaders for all diagnoses in the f8-chapter (disorders of psychological development).
-@data_loaders.register("f8_disorders")
-def f8_disorders(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f8",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("pervasive_developmental_disorders")
-def pervasive_developmental_disorders(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f84",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("miscellaneous_f8_disorders")
-def misc_f8(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=["f80", "f81", "f82", "f83", "f88", "f89"],
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-# data loaders for all diagnoses in the f9-chapter (child and adolescent disorders).
-@data_loaders.register("f9_disorders")
-def f9_disorders(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f9",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("hyperkinetic_disorders")
-def hyperkinetic_disorders(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code="f90",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("behavioural_disorders")
-def behavioural_disorders(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=["f91", "f92", "f93", "f94"],
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("tics_and_miscellaneous_f9")
-def tics_and_misc(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return from_physical_visits(
-        icd_code=["f95", "f98"],
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("gerd")
-def gerd(n_rows: Optional[int] = None) -> pd.DataFrame:
-    """Gastroesophageal reflux disease (GERD) diagnoses"""
-    return from_physical_visits(
-        icd_code="k21",
-        wildcard_icd_code=True,
-        n_rows=n_rows,
-    )
diff --git a/src/timeseriesflattener/loaders/raw/load_ids.py b/src/timeseriesflattener/loaders/raw/load_ids.py
deleted file mode 100644
index 9845cb8..0000000
--- a/src/timeseriesflattener/loaders/raw/load_ids.py
+++ /dev/null
@@ -1,26 +0,0 @@
-"""Loaders for patient IDs."""
-
-from typing import Optional
-
-import pandas as pd
-
-from psycop_feature_generation.loaders.raw.sql_load import sql_load
-
-
-def load_ids(split: str, n_rows: Optional[int] = None) -> pd.DataFrame:
-    """Loads ids for a given split.
-
-    Args:
-        split (str): Which split to load IDs from. Takes either "train", "test" or "val". # noqa: DAR102
-        n_rows: Number of rows to return. Defaults to None.
-
-    Returns:
-        pd.DataFrame: Only dw_ek_borger column with ids
-    """
-    view = f"[psycop_{split}_ids]"
-
-    sql = f"SELECT * FROM [fct].{view}"
-
-    df = sql_load(sql, database="USR_PS_FORSK", chunksize=None, n_rows=n_rows)
-
-    return df.reset_index(drop=True)
diff --git a/src/timeseriesflattener/loaders/raw/load_lab_results.py b/src/timeseriesflattener/loaders/raw/load_lab_results.py
deleted file mode 100644
index 4077f8f..0000000
--- a/src/timeseriesflattener/loaders/raw/load_lab_results.py
+++ /dev/null
@@ -1,719 +0,0 @@
-"""Loaders for lab results loading."""
-
-from typing import Optional, Union
-
-import pandas as pd
-
-from psycop_feature_generation.loaders.non_numerical_coercer import (
-    multiply_inequalities_in_df,
-)
-from psycop_feature_generation.loaders.raw.sql_load import sql_load
-from psycop_feature_generation.utils import data_loaders
-
-# pylint: disable=missing-function-docstring
-
-
-def load_non_numerical_values_and_coerce_inequalities(
-    blood_sample_id: Union[str, list[str]],
-    n_rows: Optional[int],
-    view: str,
-    ineq2mult: Optional[dict[str, float]] = None,
-) -> pd.DataFrame:
-    """Load non-numerical values for a blood sample.
-
-    Args:
-        blood_sample_id (Union[str, list]): The blood_sample_id, typically an NPU code. If a list, concatenates the values. # noqa: DAR102
-        n_rows (Optional[int]): Number of rows to return. Defaults to None.
-        view (str): The view to load from.
-        ineq2mult (dict[str, float]): A dictionary mapping inequalities to a multiplier. Defaults to None.
-
-    Returns:
-        pd.DataFrame: A dataframe with the non-numerical values.
-    """
-    cols = "dw_ek_borger, datotid_sidstesvar, svar"
-
-    if isinstance(blood_sample_id, list):
-        npu_codes = ", ".join(
-            [f"'{x}'" for x in blood_sample_id],  # pylint: disable=not-an-iterable
-        )
-
-        npu_where = f"npukode in ({npu_codes})"
-    else:
-        npu_where = f"npukode = '{blood_sample_id}'"
-
-    sql = f"SELECT {cols} FROM [fct].{view} WHERE datotid_sidstesvar IS NOT NULL AND {npu_where} AND numerisksvar IS NULL AND (left(Svar,1) = '>' OR left(Svar, 1) = '<')"
-
-    df = sql_load(
-        sql,
-        database="USR_PS_FORSK",
-        chunksize=None,
-        n_rows=n_rows,
-    )
-
-    df.rename(
-        columns={"datotid_sidstesvar": "timestamp", "svar": "value"},
-        inplace=True,
-    )
-
-    return multiply_inequalities_in_df(df, ineq2mult=ineq2mult)
-
-
-def load_numerical_values(
-    blood_sample_id: str,
-    n_rows: Optional[int],
-    view: str,
-) -> pd.DataFrame:
-    """Load numerical values for a blood sample.
-
-    Args:
-        blood_sample_id (str): The blood_sample_id, typically an NPU code.  # noqa: DAR102
-        n_rows (Optional[int]): Number of rows to return. Defaults to None.
-        view (str): The view to load from.
-
-    Returns:
-        pd.DataFrame: A dataframe with the numerical values.
-    """
-
-    cols = "dw_ek_borger, datotid_sidstesvar, numerisksvar"
-
-    if isinstance(blood_sample_id, list):
-        npu_codes = ", ".join(
-            [f"'{x}'" for x in blood_sample_id],  # pylint: disable=not-an-iterable
-        )
-
-        npu_where = f"npukode in ({npu_codes})"
-    else:
-        npu_where = f"npukode = '{blood_sample_id}'"
-
-    sql = f"SELECT {cols} FROM [fct].{view} WHERE datotid_sidstesvar IS NOT NULL AND {npu_where} AND numerisksvar IS NOT NULL"
-    df = sql_load(
-        sql,
-        database="USR_PS_FORSK",
-        chunksize=None,
-        n_rows=n_rows,
-    )
-
-    df.rename(
-        columns={"datotid_sidstesvar": "timestamp", "numerisksvar": "value"},
-        inplace=True,
-    )
-
-    return df
-
-
-def load_cancelled(
-    blood_sample_id: str,
-    n_rows: Optional[int],
-    view: str,
-) -> pd.DataFrame:
-    """Load cancelled samples for a blood sample.
-
-    Args:
-        blood_sample_id (str): The blood_sample_id, typically an NPU code.  # noqa: DAR102
-        n_rows (Optional[int]): Number of rows to return. Defaults to None.
-        view (str): The view to load from.
-
-    Returns:
-        pd.DataFrame: A dataframe with the timestamps for cancelled values.
-    """
-    cols = "dw_ek_borger, datotid_sidstesvar"
-
-    if isinstance(blood_sample_id, list):
-        npu_codes = ", ".join(
-            [f"'{x}'" for x in blood_sample_id],  # pylint: disable=not-an-iterable
-        )
-
-        npu_where = f"npukode in ({npu_codes})"
-    else:
-        npu_where = f"npukode = '{blood_sample_id}'"
-
-    sql = f"SELECT {cols} FROM [fct].{view} {npu_where} AND datotid_sidstesvar IS NOT NULL AND Svar == 'Aflyst' AND (left(Svar,1) == '>' OR left(Svar, 1) == '<')"
-
-    df = sql_load(
-        sql,
-        database="USR_PS_FORSK",
-        chunksize=None,
-        n_rows=n_rows,
-    )
-
-    # Create the value column == 1, since all timestamps here are from cancelled blood samples
-    df["value"] = 1
-
-    df.rename(
-        columns={"datotid_sidstesvar": "timestamp"},
-        inplace=True,
-    )
-
-    return df
-
-
-def load_all_values(
-    blood_sample_id: str,
-    n_rows: Optional[int],
-    view: str,
-) -> pd.DataFrame:
-    """Load all samples for a blood sample.
-
-    Args:
-        blood_sample_id (str): The blood_sample_id, typically an NPU code.  # noqa: DAR102
-        n_rows (Optional[int]): Number of rows to return. Defaults to None.
-        view (str): The view to load from.
-
-    Returns:
-        pd.DataFrame: A dataframe with all values.
-    """
-    cols = "dw_ek_borger, datotid_sidstesvar, svar"
-
-    if isinstance(blood_sample_id, list):
-        npu_codes = ", ".join(
-            [f"'{x}'" for x in blood_sample_id],  # pylint: disable=not-an-iterable
-        )
-
-        npu_where = f"npukode in ({npu_codes})"
-    else:
-        npu_where = f"npukode = '{blood_sample_id}'"
-
-    sql = f"SELECT {cols} FROM [fct].{view} WHERE datotid_sidstesvar IS NOT NULL AND {npu_where}"
-
-    df = sql_load(
-        sql,
-        database="USR_PS_FORSK",
-        chunksize=None,
-        n_rows=n_rows,
-    )
-
-    df.rename(
-        columns={"datotid_sidstesvar": "timestamp", "svar": "value"},
-        inplace=True,
-    )
-
-    return df
-
-
-def blood_sample(
-    blood_sample_id: Union[str, list],
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    """Load a blood sample.
-
-    Args:
-        blood_sample_id (Union[str, list]): The blood_sample_id, typically an NPU code. If a list, concatenates the values. # noqa: DAR102
-        n_rows: Number of rows to return. Defaults to None.
-        values_to_load (str): Which values to load. Takes either "numerical", "numerical_and_coerce", "cancelled" or "all". Defaults to None, which is coerced to "all".
-
-    Returns:
-        pd.DataFrame
-    """
-    view = "[FOR_labka_alle_blodprover_inkl_2021_feb2022]"
-
-    allowed_values_to_load = [
-        "numerical",
-        "numerical_and_coerce",
-        "cancelled",
-        "all",
-        None,
-    ]
-
-    dfs = []
-
-    if values_to_load not in allowed_values_to_load:
-        raise ValueError(
-            f"values_to_load must be one of {allowed_values_to_load}, not {values_to_load}",
-        )
-
-    if values_to_load is None:
-        values_to_load = "all"
-
-    fn_dict = {
-        "coerce": load_non_numerical_values_and_coerce_inequalities,
-        "numerical": load_numerical_values,
-        "cancelled": load_cancelled,
-        "all": load_all_values,
-    }
-
-    sources_to_load = [k for k in fn_dict if k in values_to_load]
-
-    if n_rows:
-        n_rows_per_fn = int(n_rows / len(sources_to_load))
-    else:
-        n_rows_per_fn = None
-
-    for k in sources_to_load:  # pylint: disable=invalid-name
-        dfs.append(
-            fn_dict[k](  # type: ignore
-                blood_sample_id=blood_sample_id,
-                n_rows=n_rows_per_fn,
-                view=view,
-            ),
-        )
-
-    # Concatenate dfs
-    if len(dfs) > 1:
-        df = pd.concat(dfs)
-    else:
-        df = dfs[0]
-
-    return df.reset_index(drop=True).drop_duplicates(
-        subset=["dw_ek_borger", "timestamp", "value"],
-        keep="first",
-    )
-
-
-@data_loaders.register("hba1c")
-def hba1c(
-    n_rows: Optional[int] = None, values_to_load: str = "numerical_and_coerce"
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU27300",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("scheduled_glc")
-def scheduled_glc(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    npu_suffixes = [
-        "08550",
-        "08551",
-        "08552",
-        "08553",
-        "08554",
-        "08555",
-        "08556",
-        "08557",
-        "08558",
-        "08559",
-        "08560",
-        "08561",
-        "08562",
-        "08563",
-        "08564",
-        "08565",
-        "08566",
-        "08567",
-        "08893",
-        "08894",
-        "08895",
-        "08896",
-        "08897",
-        "08898",
-        "08899",
-        "08900",
-        "08901",
-        "08902",
-        "08903",
-        "08904",
-        "08905",
-        "08906",
-        "08907",
-        "08908",
-        "08909",
-        "08910",
-        "08911",
-        "08912",
-        "08913",
-        "08914",
-        "08915",
-        "08916",
-    ]
-
-    blood_sample_ids = [f"NPU{suffix}" for suffix in npu_suffixes]
-
-    return blood_sample(
-        blood_sample_id=blood_sample_ids,
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("unscheduled_p_glc")
-def unscheduled_p_glc(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    npu_suffixes = [
-        "02192",
-        "21533",
-        "21531",
-    ]
-
-    dnk_suffixes = ["35842"]
-
-    blood_sample_ids = [f"NPU{suffix}" for suffix in npu_suffixes]
-    blood_sample_ids += [f"DNK{suffix}" for suffix in dnk_suffixes]
-
-    return blood_sample(
-        blood_sample_id=blood_sample_ids,
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("triglycerides")
-def triglycerides(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU04094",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("fasting_triglycerides")
-def fasting_triglycerides(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU03620",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("hdl")
-def hdl(
-    n_rows: Optional[int] = None, values_to_load: str = "numerical_and_coerce"
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU01567",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("ldl")
-def ldl(
-    n_rows: Optional[int] = None, values_to_load: str = "numerical_and_coerce"
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id=["NPU01568", "AAB00101"],
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("fasting_ldl")
-def fasting_ldl(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id=["NPU10171", "AAB00102"],
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("alat")
-def alat(
-    n_rows: Optional[int] = None, values_to_load: str = "numerical_and_coerce"
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU19651",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("asat")
-def asat(
-    n_rows: Optional[int] = None, values_to_load: str = "numerical_and_coerce"
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU19654",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("lymphocytes")
-def lymphocytes(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU02636",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("leukocytes")
-def leukocytes(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU02593",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("crp")
-def crp(
-    n_rows: Optional[int] = None, values_to_load: str = "numerical_and_coerce"
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU19748",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("creatinine")
-def creatinine(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id=["NPU18016", "ASS00355", "ASS00354"],
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("egfr")
-def egfr(
-    n_rows: Optional[int] = None, values_to_load: str = "numerical_and_coerce"
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id=["DNK35302", "DNK35131", "AAB00345", "AAB00343"],
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("albumine_creatinine_ratio")
-def albumine_creatinine_ratio(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU19661",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("cyp21a2")
-def cyp21a2(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU19053",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("cyp2c19")
-def cyp2c19(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU19309",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("cyp2c9")
-def cyp2c9(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU32095",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("cyp3a5")
-def cyp3a5(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU27992",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("cyp2d6")
-def cyp2d6(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU19308",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("p_lithium")
-def p_lithium(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU02613",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("p_clozapine")
-def p_clozapine(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU04114",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("p_olanzapine")
-def p_olanzapine(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU09358",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("p_aripiprazol")
-def p_aripiprazol(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU26669",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("p_risperidone")
-def p_risperidone(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU04868",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("p_paliperidone")
-def p_paliperidone(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU18359",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("p_haloperidol")
-def p_haloperidol(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU03937",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("p_amitriptyline")
-def p_amitriptyline(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU01224",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("p_nortriptyline")
-def p_nortriptyline(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU02923",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("p_clomipramine")
-def p_clomipramine(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU01616",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("p_paracetamol")
-def p_paracetamol(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU03024",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("p_ibuprofen")
-def p_ibuprofen(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU08794",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
-
-
-@data_loaders.register("p_ethanol")
-def p_ethanol(
-    n_rows: Optional[int] = None,
-    values_to_load: str = "numerical_and_coerce",
-) -> pd.DataFrame:
-    return blood_sample(
-        blood_sample_id="NPU01992",
-        n_rows=n_rows,
-        values_to_load=values_to_load,
-    )
diff --git a/src/timeseriesflattener/loaders/raw/load_medications.py b/src/timeseriesflattener/loaders/raw/load_medications.py
deleted file mode 100644
index 92c08d1..0000000
--- a/src/timeseriesflattener/loaders/raw/load_medications.py
+++ /dev/null
@@ -1,641 +0,0 @@
-"""Loaders for medications."""
-from typing import Optional, Union
-
-import pandas as pd
-from wasabi import msg
-
-from psycop_feature_generation.loaders.raw.utils import load_from_codes
-from psycop_feature_generation.utils import data_loaders
-
-# pylint: disable=missing-function-docstring
-
-
-def load(
-    atc_code: Union[str, list[str]],
-    output_col_name: Optional[str] = None,
-    load_prescribed: Optional[bool] = False,
-    load_administered: Optional[bool] = True,
-    wildcard_code: Optional[bool] = True,
-    n_rows: Optional[int] = None,
-    exclude_atc_codes: Optional[list[str]] = None,
-) -> pd.DataFrame:
-    """Load medications. Aggregates prescribed/administered if both true. If
-    wildcard_atc_code, match from atc_code*. Aggregates all that match. Beware
-    that data is incomplete prior to sep. 2016 for prescribed medications.
-
-    Args:
-        atc_code (str): ATC-code prefix to load. Matches atc_code_prefix*.
-            Aggregates all.
-        output_col_name (str, optional): Name of output_col_name. Contains 1 if
-            atc_code matches atc_code_prefix, 0 if not.Defaults to
-            {atc_code_prefix}_value.
-        load_prescribed (bool, optional): Whether to load prescriptions. Defaults to
-            False. Beware incomplete until sep 2016.
-        load_administered (bool, optional): Whether to load administrations.
-            Defaults to True.
-        wildcard_code (bool, optional): Whether to match on atc_code* or
-            atc_code.
-        n_rows (int, optional): Number of rows to return. Defaults to None, in which case all rows are returned.
-        exclude_atc_codes (list[str], optional): Drop rows if atc_code is a direct match to any of these. Defaults to None.
-
-    Returns:
-        pd.DataFrame: Cols: dw_ek_borger, timestamp, {atc_code_prefix}_value = 1
-    """
-
-    if load_prescribed:
-        msg.warn(
-            "Beware, there are missing prescriptions until september 2016. "
-            "Hereafter, data is complete. See the wiki (OBS: Medication) for more details.",
-        )
-
-    df = pd.DataFrame()
-
-    if load_prescribed and load_administered:
-        n_rows = int(n_rows / 2) if n_rows else None
-
-    if load_prescribed:
-        df_medication_prescribed = load_from_codes(
-            codes_to_match=atc_code,
-            code_col_name="atc",
-            source_timestamp_col_name="datotid_ordinationstart",
-            view="FOR_Medicin_ordineret_inkl_2021_feb2022",
-            output_col_name=output_col_name,
-            match_with_wildcard=wildcard_code,
-            n_rows=n_rows,
-            exclude_codes=exclude_atc_codes,
-            load_diagnoses=False,
-        )
-
-        df = pd.concat([df, df_medication_prescribed])
-
-    if load_administered:
-        df_medication_administered = load_from_codes(
-            codes_to_match=atc_code,
-            code_col_name="atc",
-            source_timestamp_col_name="datotid_administration_start",
-            view="FOR_Medicin_administreret_inkl_2021_feb2022",
-            output_col_name=output_col_name,
-            match_with_wildcard=wildcard_code,
-            n_rows=n_rows,
-            exclude_codes=exclude_atc_codes,
-            load_diagnoses=False,
-        )
-        df = pd.concat([df, df_medication_administered])
-
-    if output_col_name is None:
-        if isinstance(atc_code, list):
-            # Joint list of atc_codes
-            output_col_name = "_".join(atc_code)
-        else:
-            output_col_name = atc_code
-
-    df.rename(
-        columns={
-            output_col_name: "value",
-        },
-        inplace=True,
-    )
-
-    return df.reset_index(drop=True).drop_duplicates(
-        subset=["dw_ek_borger", "timestamp", "value"],
-        keep="first",
-    )
-
-
-def concat_medications(
-    output_col_name: str,
-    atc_code_prefixes: list[str],
-    n_rows: Optional[int] = None,
-) -> pd.DataFrame:
-    """Aggregate multiple blood_sample_ids (typically NPU-codes) into one
-    column.
-
-    Args:
-        output_col_name (str): Name for new column.  # noqa: DAR102
-        atc_code_prefixes (list[str]): list of atc_codes.
-        n_rows (int, optional): Number of atc_codes to aggregate. Defaults to None.
-
-    Returns:
-        pd.DataFrame
-    """
-    dfs = [
-        load(
-            atc_code=f"{id}",
-            output_col_name=output_col_name,
-            n_rows=n_rows,
-        )
-        for id in atc_code_prefixes
-    ]
-
-    return (
-        pd.concat(dfs, axis=0)
-        .drop_duplicates(
-            subset=["dw_ek_borger", "timestamp", "value"],
-            keep="first",
-        )
-        .reset_index(drop=True)
-    )
-
-
-# data_loaders primarly used in psychiatry
-@data_loaders.register("antipsychotics")
-def antipsychotics(n_rows: Optional[int] = None) -> pd.DataFrame:
-    """All antipsyhotics, except Lithium. Lithium is typically considered a mood stabilizer, not an antipsychotic."""
-    return load(
-        atc_code="N05A",
-        load_prescribed=True,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-        exclude_atc_codes=["N05AN01"],
-    )
-
-
-# 1. generation antipsychotics [flupentixol, pimozid, haloperidol, zuclopenthixol, melperon,pipamperon, chlorprotixen]
-@data_loaders.register("first_gen_antipsychotics")
-def first_gen_antipsychotics(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code=[
-            "N05AF01",
-            "N05AG02",
-            "N05AD01",
-            "N05AF05",
-            "N05AD03",
-            "N05AD05",
-            "N05AF03",
-        ],
-        load_prescribed=True,
-        load_administered=True,
-        wildcard_code=False,
-        n_rows=n_rows,
-    )
-
-
-# 2. generation antipsychotics [amisulpride, aripiprazole,asenapine, brexpiprazole, cariprazine, lurasidone, olanzapine, paliperidone, Quetiapine, risperidone, sertindol]
-@data_loaders.register("second_gen_antipsychotics")
-def second_gen_antipsychotics(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code=[
-            "N05AL05",
-            "N05AX12",
-            "N05AH05",
-            "N05AX16",
-            "N05AX15",
-            "N05AE02",
-            "N05AE05",
-            "N05AH03",
-            "N05AX13",
-            "N05AH04",
-            "N05AX08",
-            "N05AE04",
-            "N05AE03",
-        ],
-        load_prescribed=True,
-        load_administered=True,
-        wildcard_code=False,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("top_10_weight_gaining_antipsychotics")
-def top_10_weight_gaining_antipsychotics(n_rows: Optional[int] = None) -> pd.DataFrame:
-    """Top 10 weight gaining antipsychotics based on Huhn et al. 2019. Only 5 of them are marketed in Denmark."""
-    return load(
-        atc_code=[
-            "N05AH03",
-            "N05AE03",
-            "N05AH04",
-            "N05AX13",
-            "N05AX08",
-        ],
-        load_prescribed=True,
-        load_administered=True,
-        wildcard_code=False,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("olanzapine")
-def olanzapine(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="N05AH03",
-        load_prescribed=True,
-        load_administered=True,
-        wildcard_code=False,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("clozapine")
-def clozapine(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="N05AH02",
-        load_prescribed=True,
-        load_administered=True,
-        wildcard_code=False,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("anxiolytics")
-def anxiolytics(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="N05B",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("benzodiazepines")
-def benzodiazepines(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="N05BA",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("benzodiazepine_related_sleeping_agents")
-def benzodiazepine_related_sleeping_agents(
-    n_rows: Optional[int] = None,
-) -> pd.DataFrame:
-    return load(
-        atc_code=["N05CF01", "N05CF02"],
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("pregabaline")
-def pregabaline(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="N03AX16",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("hypnotics and sedatives")
-def hypnotics(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="N05C",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("antidepressives")
-def antidepressives(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="N06A",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-# SSRIs [escitalopram, citalopram, fluvoxamin, fluoxetin, paroxetin]
-@data_loaders.register("ssri")
-def ssri(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="N06AB",
-        load_prescribed=True,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-# SNRIs [duloxetin, venlafaxin]
-@data_loaders.register("snri")
-def snri(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code=["N06AX21", "N06AX16"],
-        load_prescribed=True,
-        load_administered=True,
-        wildcard_code=False,
-        n_rows=n_rows,
-    )
-
-
-# TCAs
-@data_loaders.register("tca")
-def tca(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="N06AA",
-        load_prescribed=True,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("selected_nassa")
-def selected_nassa(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code=["N06AX11", "N06AX03"],
-        load_prescribed=True,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("lithium")
-def lithium(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="N05AN01",
-        load_prescribed=True,
-        load_administered=True,
-        wildcard_code=False,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("valproate")
-def valproate(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="N03AG01",
-        load_prescribed=True,
-        load_administered=True,
-        wildcard_code=False,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("lamotrigine")
-def lamotrigine(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="N03AX09",
-        load_prescribed=True,
-        load_administered=True,
-        wildcard_code=False,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("hyperactive disorders medications")
-def hyperactive_disorders_medications(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="N06B",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("dementia medications")
-def dementia_medications(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="N06D",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("anti-epileptics")
-def anti_epileptics(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="N03",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-# medications used in alcohol abstinence treatment [thiamin, b-combin, klopoxid, fenemal]
-@data_loaders.register("alcohol_abstinence")
-def alcohol_abstinence(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code=["A11DA01", "A11EA", "N05BA02", "N03AA02"],
-        load_prescribed=True,
-        load_administered=True,
-        wildcard_code=False,
-        n_rows=n_rows,
-    )
-
-
-# data loaders for medications primarily used outside psychiatry
-@data_loaders.register("alimentary_tract_and_metabolism_medications")
-def alimentary_medications(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="A",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("blood_and_blood_forming_organs_medications")
-def blood_medications(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="B",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("cardiovascular_medications")
-def cardiovascular_medications(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="C",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("dermatologicals")
-def dermatological_medications(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="D",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("genito_urinary_system_and_sex_hormones_medications")
-def genito_sex_medications(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="G",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("systemic_hormonal_preparations")
-def hormonal_medications(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="H",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("antiinfectives")
-def antiinfectives(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="J",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("antineoplastic")
-def antineoplastic(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="L",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("musculoskeletal_medications")
-def musculoskeletal_medications(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="M",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("nervous_system_medications")
-def nervous_system_medications(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="N",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("analgesics")
-def analgesic(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="N02",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("antiparasitic")
-def antiparasitic(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="P",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("respiratory_medications")
-def respiratory_medications(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="R",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("sensory_organs_medications")
-def sensory_medications(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="S",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("various_medications")
-def various_medications(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="V",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("statins")
-def statins(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="C10AA",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("antihypertensives")
-def antihypertensives(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="C02",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("diuretics")
-def diuretics(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return load(
-        atc_code="C07",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("gerd_drugs")
-def gerd_drugs(n_rows: Optional[int] = None) -> pd.DataFrame:
-    """Gastroesophageal reflux disease (GERD) drugs"""
-    return load(
-        atc_code="A02",
-        load_prescribed=False,
-        load_administered=True,
-        wildcard_code=True,
-        n_rows=n_rows,
-    )
diff --git a/src/timeseriesflattener/loaders/raw/load_structured_sfi.py b/src/timeseriesflattener/loaders/raw/load_structured_sfi.py
deleted file mode 100644
index f4edd38..0000000
--- a/src/timeseriesflattener/loaders/raw/load_structured_sfi.py
+++ /dev/null
@@ -1,139 +0,0 @@
-"""Loaders for structured SFI-data."""
-
-# pylint: disable = missing-function-docstring
-
-from typing import Optional
-
-import pandas as pd
-
-from psycop_feature_generation.loaders.raw.sql_load import sql_load
-from psycop_feature_generation.utils import data_loaders
-
-
-def sfi_loader(
-    aktivitetstypenavn: Optional[str] = None,
-    elementledetekst: Optional[str] = None,
-    n_rows: Optional[int] = None,
-    value_col: str = "numelementvaerdi",
-) -> pd.DataFrame:
-    """Load structured_sfi data. By default returns entire structured_sfi data
-    view with numelementværdi as the value column.
-
-    Args:
-        aktivitetstypenavn (str): Type of structured_sfi, e.g. 'broeset_violence_checklist', 'selvmordsvurdering'. Defaults to None. # noqa: DAR102
-        elementledetekst (str): elementledetekst which specifies which sub-element of the SFI, e.g. 'Sum', "Selvmordstanker". Defaults to None.
-        n_rows: Number of rows to return. Defaults to None which returns entire structured_sfi data view.
-        value_col: Column to return as value col. Defaults to 'numelementvaerdi'.
-
-    Returns:
-        pd.DataFrame
-    """
-    view = "[FOR_SFI_uden_fritekst_resultater_psyk_somatik_inkl_2021]"
-    sql = f"SELECT dw_ek_borger, datotid_resultat_udfoert, {value_col} FROM [fct].{view} WHERE datotid_resultat_udfoert IS NOT NULL"
-
-    if elementledetekst:
-        sql += f" AND aktivitetstypenavn = '{aktivitetstypenavn}'"
-    if aktivitetstypenavn:
-        sql += f" AND elementledetekst = '{elementledetekst}'"
-
-    df = sql_load(sql, database="USR_PS_FORSK", chunksize=None, n_rows=n_rows)
-
-    # Drop duplicate rows
-    df = df.drop_duplicates(keep="first")
-
-    # Drop rows with duplicate dw_ek_borger and datotid_resultat_udfoert
-    # Data contained rows with scores reported at the same time for the same patient but with different values
-    df = df.drop_duplicates(
-        subset=["datotid_resultat_udfoert", "dw_ek_borger"],
-        keep="first",
-    )
-
-    df.rename(
-        columns={
-            "datotid_resultat_udfoert": "timestamp",
-            value_col: "value",
-        },
-        inplace=True,
-    )
-
-    return df.reset_index(drop=True)
-
-
-@data_loaders.register("broeset_violence_checklist")
-def broeset_violence_checklist(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return sfi_loader(
-        aktivitetstypenavn="Brøset Violence Checkliste (BVC)",
-        elementledetekst="Sum",
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("selvmordsrisiko")
-def selvmordsrisiko(n_rows: Optional[int] = None) -> pd.DataFrame:
-    df = sfi_loader(
-        aktivitetstypenavn="Screening for selvmordsrisiko",
-        elementledetekst="ScrSelvmordlRisikoniveauKonkl",
-        n_rows=n_rows,
-        value_col="elementkode",
-    )
-
-    df["value"] = df["value"].replace(
-        to_replace=[
-            "010ScrSelvmordKonklRisikoniveau1",
-            "020ScrSelvmordKonklRisikoniveau2",
-            "030ScrSelvmordKonklRisikoniveau3",
-        ],
-        value=[1, 2, 3],
-        regex=False,
-    )
-
-    return df
-
-
-@data_loaders.register("hamilton_d17")
-def hamilton_d17(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return sfi_loader(
-        aktivitetstypenavn="Vurdering af depressionssværhedsgrad med HAM-D17",
-        elementledetekst="Samlet score HAM-D17",
-        n_rows=n_rows,
-    )
-
-
-@data_loaders.register("mas_m")
-def mas_m(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return sfi_loader(
-        aktivitetstypenavn="MAS-M maniscoringsskema (Modificeret Bech-Rafaelsen Maniskala)",
-        elementledetekst="MAS-M score",
-        n_rows=n_rows,
-        value_col="numelementvaerdi",
-    )
-
-
-@data_loaders.register("height_in_cm")
-def height_in_cm(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return sfi_loader(
-        aktivitetstypenavn="Måling af patienthøjde (cm)",
-        elementledetekst="Højde i cm",
-        n_rows=n_rows,
-        value_col="numelementvaerdi",
-    )
-
-
-@data_loaders.register("weight_in_kg")
-def weight_in_kg(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return sfi_loader(
-        aktivitetstypenavn="Måling af patientvægt (kg)",
-        elementledetekst="Vægt i kg",
-        n_rows=n_rows,
-        value_col="numelementvaerdi",
-    )
-
-
-@data_loaders.register("bmi")
-def bmi(n_rows: Optional[int] = None) -> pd.DataFrame:
-    return sfi_loader(
-        aktivitetstypenavn="Bestemmelse af Body Mass Index (BMI)",
-        elementledetekst="BMI",
-        n_rows=n_rows,
-        value_col="numelementvaerdi",
-    )
diff --git a/src/timeseriesflattener/loaders/raw/load_t2d_outcomes.py b/src/timeseriesflattener/loaders/raw/load_t2d_outcomes.py
deleted file mode 100644
index d707fcc..0000000
--- a/src/timeseriesflattener/loaders/raw/load_t2d_outcomes.py
+++ /dev/null
@@ -1,51 +0,0 @@
-"""Loaders for T2D outcomes."""
-
-# pylint: disable=missing-function-docstring
-
-from typing import Optional
-
-import pandas as pd
-from wasabi import msg
-
-from psycop_feature_generation.loaders.raw.sql_load import sql_load
-from psycop_feature_generation.utils import data_loaders
-
-
-@data_loaders.register("t2d")
-def t2d(n_rows: Optional[int] = None) -> pd.DataFrame:
-    msg.info("Loading t2d event times")
-
-    df = sql_load(
-        "SELECT dw_ek_borger, timestamp FROM [fct].[psycop_t2d_first_diabetes_t2d] WHERE timestamp IS NOT NULL",
-        database="USR_PS_FORSK",
-        chunksize=None,
-        format_timestamp_cols_to_datetime=True,
-        n_rows=n_rows,
-    )
-    df["value"] = 1
-
-    # 2 duplicates, dropping
-    df = df.drop_duplicates(keep="first")
-
-    msg.good("Finished loading t2d event times")
-    return df.reset_index(drop=True)
-
-
-@data_loaders.register("any_diabetes")
-def any_diabetes(n_rows: Optional[int] = None):
-    df = sql_load(
-        "SELECT * FROM [fct].[psycop_t2d_first_diabetes_any] WHERE timestamp IS NOT NULL",
-        database="USR_PS_FORSK",
-        chunksize=None,
-        n_rows=n_rows,
-    )
-
-    df = df[["dw_ek_borger", "datotid_first_diabetes_any"]]
-    df["value"] = 1
-
-    df.rename(columns={"datotid_first_diabetes_any": "timestamp"}, inplace=True)
-    df["timestamp"] = pd.to_datetime(df["timestamp"]).dt.tz_localize(None)
-
-    msg.good("Finished loading any_diabetes event times")
-    output = df[["dw_ek_borger", "timestamp", "value"]]
-    return output.reset_index(drop=True)
diff --git a/src/timeseriesflattener/loaders/raw/load_text.py b/src/timeseriesflattener/loaders/raw/load_text.py
deleted file mode 100644
index 2f532e5..0000000
--- a/src/timeseriesflattener/loaders/raw/load_text.py
+++ /dev/null
@@ -1,460 +0,0 @@
-# """Load text data from a database and featurise it using a tf-idf
-# vectorizer."""
-
-# # pylint: disable=E0211,E0213,missing-function-docstring
-
-# from functools import partial
-# from multiprocessing import Pool
-# from pathlib import Path
-# from typing import Optional, Union
-
-# import dill as pkl
-# import pandas as pd
-
-# # import torch
-# from transformers import AutoModel, AutoTokenizer
-# from transformers.modeling_outputs import BaseModelOutputWithPoolingAndCrossAttentions
-
-# from psycop_feature_generation.loaders.raw.sql_load import sql_load
-# from psycop_feature_generation.utils import PROJECT_ROOT, data_loaders
-
-
-# def get_all_valid_note_types() -> set[str]:
-#     """Returns a set of valid note types. Notice that 'Konklusion' is replaced
-#     by 'Vurdering/konklusion' in 2020, so make sure to use both. 'Ordination'
-#     was replaced by 'Ordination, Psykiatry' in 2022, but 'Ordination,
-#     Psykiatri' is not included in the table. Use with caution.
-
-#     Returns:
-#         Set[str]: Set of valid note types
-#     """
-#     return {
-#         "Observation af patient, Psykiatri",
-#         "Samtale med behandlingssigte",
-#         "Ordination",  # OBS replaced "Ordination, Psykiatri" in 01/02-22
-#         # but is not included in this table. Use with caution
-#         "Aktuelt psykisk",
-#         "Aktuelt socialt, Psykiatri",
-#         "Aftaler, Psykiatri",
-#         "Medicin",
-#         "Aktuelt somatisk, Psykiatri",
-#         "Objektivt psykisk",
-#         "Kontaktårsag",
-#         "Telefonkonsultation",
-#         "Journalnotat",
-#         "Telefonnotat",
-#         "Objektivt, somatisk",
-#         "Plan",
-#         "Semistruktureret diagnostisk interview",
-#         "Vurdering/konklusion",
-#     }
-
-
-# def _load_notes_for_year(
-#     note_types: Union[str, list[str]],
-#     year: str,
-#     view: Optional[str] = "FOR_SFI_fritekst_resultat_udfoert_i_psykiatrien_aendret",
-#     n_rows: Optional[int] = None,
-# ) -> pd.DataFrame:
-#     """Loads clinical notes from sql from a specified year and matching
-#     specified note types.
-
-#     Args:
-#         note_names (Union[str, list[str]]): Which types of notes to load.
-#         year (str): Which year to load
-#         view (str, optional): Which table to load.
-#             Defaults to "[FOR_SFI_fritekst_resultat_udfoert_i_psykiatrien_aendret".
-#         n_rows (Optional[int], optional): Number of rows to load. Defaults to None.
-
-#     Returns:
-#         pd.DataFrame: Dataframe with clinical notes
-#     """
-
-#     sql = (
-#         "SELECT dw_ek_borger, datotid_senest_aendret_i_sfien, fritekst"
-#         + f" FROM [fct].[{view}_{year}_inkl_2021_feb2022]"
-#         + f" WHERE overskrift IN {note_types}"
-#     )
-#     return sql_load(
-#         sql,
-#         database="USR_PS_FORSK",
-#         chunksize=None,
-#         n_rows=n_rows,
-#     )
-
-
-# def _tfidf_featurize(
-#     df: pd.DataFrame,
-#     tfidf_path: Path,
-#     text_col: str = "text",
-# ) -> pd.DataFrame:
-#     """TF-IDF featurize text. Assumes `df` to have a column named `text`.
-
-#     Args:
-#         df (pd.DataFrame): Dataframe with text column
-#         tfidf_path (Optional[Path]): Path to a sklearn tf-idf vectorizer
-#         text_col (str, optional): Name of text column. Defaults to "text".
-
-#     Returns:
-#         pd.DataFrame: Original dataframe with tf-idf features appended
-#     """
-#     with open(tfidf_path, "rb") as f:
-#         tfidf = pkl.load(f)
-
-#     vocab = ["tfidf-" + word for word in tfidf.get_feature_names()]
-
-#     text = df[text_col].values
-#     df = df.drop(text_col, axis=1).reset_index(drop=True)
-
-#     text = tfidf.transform(text)
-#     text = pd.DataFrame(text.toarray(), columns=vocab)
-#     return pd.concat([df, text], axis=1)
-
-
-# def _mean_pooling(
-#     model_output: BaseModelOutputWithPoolingAndCrossAttentions,
-#     attention_mask: torch.Tensor,
-# ) -> torch.Tensor:
-#     """Mean Pooling - take attention mask into account for correct averaging.
-
-#     Args:
-#         model_output (BaseModelOutputWithPoolingAndCrossAttentions): model output from pretrained Huggingface transformer
-#         attention_mask (torch.Tensor): attention mask from from pretrained Hugginface tokenizer
-
-#     Returns:
-#         np.ndarray: numpy array with mean pooled embeddings
-#     """
-#     token_embeddings = model_output[
-#         0
-#     ]  # first element of model_output contains all token embeddings
-#     input_mask_expanded = (
-#         attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
-#     )
-#     return torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp(
-#         input_mask_expanded.sum(1),
-#         min=1e-9,
-#     )
-
-
-def _chunk_text(text: str, seq_length: int) -> list[str]:
-    """Chunk text into sequences of length `seq_length`, where `seq_length`
-    refers to number of words.
-
-    Args:
-        text (str): text to chunk
-        seq_length (int): length of sequence (number of words)
-    Returns:
-        list[str]: list of text chunks
-    """
-    words = text.split(" ")
-    # If text is not longer than allowed sequence length, extract and save embeddings
-    if len(words) <= seq_length:
-        return [text]
-    # If text is longer than allowed sequence length, split text into chunks
-    else:
-        words_in_chunks = [
-            words[i - seq_length : i]
-            for i in range(seq_length, len(words) + seq_length, seq_length)
-        ]
-        chunks = [
-            " ".join(word_list)
-            for word_list in words_in_chunks
-            if len(word_list) == seq_length
-        ]  # drop small remainder of shorter size
-        return chunks
-
-
-# def _huggingface_featurize(
-#     df: pd.DataFrame,
-#     model_id: str = "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
-#     text_col: str = "text",
-# ) -> pd.DataFrame:
-#     """Featurize text using a huggingface model and generate a dataframe with
-#     the embeddings. If the text is longer than the maximum sequence length of
-#     the model, the text is split into chunks and embeddings are averaged across
-#     chunks.
-
-#     Args:
-#         df (pd.DataFrame): Dataframe with text column
-#         model_id (str): Which huggingface model to use. See https://huggingface.co/models for a list of models. Assumes the model is a transformer model and has both a tokenizer and a model.
-#         text_col (str, optional): Name of text column. Defaults to "text".
-
-#     Returns:
-#         pd.DataFrame: Original dataframe with huggingface embeddings appended
-
-#     Example:
-#         >>> p = PROJECT_ROOT / "tests" / "test_data" / "raw"
-#         >>> huggingface_model_id = "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"
-#         >>> df_p = p / "synth_txt_data.csv"
-
-#         >>> df = pd.read_csv(df_p)
-#         >>> df = df.dropna()
-
-#         >>> x = _huggingface_featurize(df, huggingface_model_id)
-#     """
-#     tokenizer = AutoTokenizer.from_pretrained(model_id)
-#     model = AutoModel.from_pretrained(model_id)
-
-#     df = df[df[text_col].notna()]
-#     text = df[text_col].values
-#     df = df.drop(text_col, axis=1)
-
-#     max_seq_length = int(
-#         tokenizer.model_max_length / 1.5,
-#     )  # allowing space for more word piece tokens than words in original sequence
-
-#     list_of_embeddings = []
-#     for txt in text:
-#         chunks = _chunk_text(txt, max_seq_length)
-
-#         encoded_input = tokenizer(
-#             chunks,
-#             padding=True,
-#             truncation=True,
-#             return_tensors="pt",
-#         )
-
-#         with torch.no_grad():
-#             model_output = model(**encoded_input)
-
-#         embedding = _mean_pooling(model_output, encoded_input["attention_mask"])
-
-#         if len(chunks) > 1:
-#             list_of_embeddings.append(torch.mean(embedding, axis=0).numpy())  # type: ignore
-#         else:
-#             list_of_embeddings.append(embedding.numpy()[0])
-
-#     embeddings_df = pd.DataFrame(list_of_embeddings)
-#     embeddings_df.columns = [
-#         "embedding-" + str(dimension) for dimension in range(embeddings_df.shape[1])
-#     ]
-
-#     return pd.concat([df, embeddings_df], axis=1)
-
-
-# def _load_and_featurize_notes_per_year(
-#     year: str,
-#     note_types: Union[str, list[str]],
-#     view: str,
-#     n_rows: int,
-#     featurizer: str,
-#     featurizer_kwargs: dict,
-# ) -> pd.DataFrame:
-#     """Loads clinical notes and features them.
-
-#     Args:
-#         note_types (Union[str, list[str]]): Which note types to load.
-#         year (str): Which year to load
-#         view (str): Which view to load
-#         n_rows (int): How many rows to load
-#         featurizer (str): Which featurizer to use (tfidf or huggingface)
-#         featurizer_kwargs (dict): kwargs for the featurizer
-
-#     Returns:
-#         pd.DataFrame: Dataframe of notes and features
-#     """
-
-#     df = _load_notes_for_year(
-#         note_types=note_types,
-#         year=year,
-#         view=view,
-#         n_rows=n_rows,
-#     )
-#     if featurizer == "tfidf":
-#         df = _tfidf_featurize(df, **featurizer_kwargs)
-#     elif featurizer == "huggingface":
-#         df = _huggingface_featurize(df, **featurizer_kwargs)
-#     return df
-
-
-# def load_and_featurize_notes(
-#     note_types: Union[str, list[str]],
-#     featurizer: str,
-#     featurizer_kwargs: Optional[dict] = None,
-#     n_rows: Optional[int] = None,
-# ) -> pd.DataFrame:
-#     """Loads all clinical notes that match the specified note from all years.
-#     Featurizes the notes using the specified featurizer (tf-idf or huggingface
-#     model). Kwargs passed to.
-
-#     Args:
-#         note_types (Union[str, list[str]]): Which note types to load. See
-#             `get_all_valid_note_types()` for valid note types.
-#         featurizer (str): Which featurizer to use. Either 'tf-idf' or 'huggingface' or
-#             `None` to return the raw text.
-#         featurizer_kwargs (Optional[dict]): Kwargs passed to the featurizer. Defaults to None.
-#             For tf-idf, this is `tfidf_path` to the vectorizer. For huggingface,
-#             this is `model_id` to the model.
-#         n_rows (Optional[int], optional): How many rows to load. Defaults to None.
-
-#     Raises:
-#         ValueError: If given invalid featurizer
-#         ValueError: If given invlaid note type
-
-#     Returns:
-#         pd.DataFrame: Featurized clinical notes
-#     """
-
-#     valid_featurizers = {"tfidf", "huggingface", None}
-#     if featurizer not in valid_featurizers:
-#         raise ValueError(
-#             f"featurizer must be one of {valid_featurizers}, got {featurizer}",
-#         )
-
-#     if isinstance(note_types, str):
-#         note_types = list(note_types)  # pylint: disable=W0642
-#     # check for invalid note types
-#     if not set(note_types).issubset(get_all_valid_note_types()):
-#         raise ValueError(
-#             "Invalid note type. Valid note types are: "
-#             + str(get_all_valid_note_types()),
-#         )
-
-#     # convert note_types to sql query
-#     note_types = "('" + "', '".join(note_types) + "')"  # pylint: disable=W0642
-
-#     view = "FOR_SFI_fritekst_resultat_udfoert_i_psykiatrien_aendret"
-
-#     load_and_featurize = partial(
-#         _load_and_featurize_notes_per_year,
-#         note_types=note_types,
-#         view=view,
-#         n_rows=n_rows,
-#         featurizer=featurizer,
-#         featurizer_kwargs=featurizer_kwargs,
-#     )
-
-#     years = list(range(2011, 2022))
-
-#     with Pool(processes=len(years)) as p:
-#         dfs = p.map(load_and_featurize, [str(y) for y in years])
-
-#     df = pd.concat(dfs)
-
-#     df = df.rename(
-#         {"datotid_senest_aendret_i_sfien": "timestamp", "fritekst": "text"},
-#         axis=1,
-#     )
-#     return df
-
-
-# @data_loaders.register("all_notes")
-# def load_all_notes(
-#     featurizer: str,
-#     n_rows: Optional[int] = None,
-#     featurizer_kwargs: Optional[dict] = None,
-# ) -> pd.DataFrame:
-#     """Returns all notes from all years. Featurizes the notes using the
-#     specified featurizer ('tfidf', 'huggingface', or `None` for raw text).
-#     `featurizer_kwargs` are passed to the featurizer (e.g. "tfidf_path" for
-#     tfidf, and "model_id" for huggingface).
-
-#     Args:
-#         featurizer (str): Which featurizer to use. Either 'tf-idf', 'huggingface', or None
-#         n_rows (Optional[int], optional): Number of rows to load. Defaults to None.
-#         featurizer_kwargs (Optional[dict], optional): Keyword arguments passed to
-#             the featurizer. Defaults to None.
-
-#     Returns:
-#         pd.DataFrame: (Featurized) notes
-#     """
-#     return load_and_featurize_notes(
-#         note_types=get_all_valid_note_types(),
-#         featurizer=featurizer,
-#         n_rows=n_rows,
-#         featurizer_kwargs=featurizer_kwargs,
-#     )
-
-
-# @data_loaders.register("aktuelt_psykisk")
-# def load_aktuel_psykisk(
-#     featurizer: str,
-#     n_rows: Optional[int] = None,
-#     featurizer_kwargs: Optional[dict] = None,
-# ) -> pd.DataFrame:
-#     """Returns 'Aktuelt psykisk' notes from all years. Featurizes the notes
-#     using the specified featurizer ('tfidf', 'huggingface', or `None` for raw
-#     text). `featurizer_kwargs` are passed to the featurizer (e.g. "tfidf_path"
-#     for tfidf, and "model_id" for huggingface).
-
-#     Args:
-#         featurizer (str): Which featurizer to use. Either 'tf-idf', 'huggingface', or None
-#         n_rows (Optional[int], optional): Number of rows to load. Defaults to None.
-#         featurizer_kwargs (Optional[dict], optional): Keyword arguments passed to
-#             the featurizer. Defaults to None.
-
-#     Returns:
-#         pd.DataFrame: (Featurized) notes
-#     """
-#     return load_and_featurize_notes(
-#         note_types="Aktuelt psykisk",
-#         featurizer=featurizer,
-#         n_rows=n_rows,
-#         featurizer_kwargs=featurizer_kwargs,
-#     )
-
-
-# @data_loaders.register("load_note_types")
-# def load_arbitrary_notes(
-#     note_names: Union[str, list[str]],
-#     featurizer: str,
-#     n_rows: Optional[int] = None,
-#     featurizer_kwargs: Optional[dict] = None,
-# ) -> pd.DataFrame:
-#     """Returns one or multiple note types from all years. Featurizes the notes
-#     using the specified featurizer ('tfidf', 'huggingface', or `None` for raw
-#     text). `featurizer_kwargs` are passed to the featurizer (e.g. "tfidf_path"
-#     for tfidf, and "model_id" for huggingface).
-
-#     Args:
-#         note_names (Union[str, list[str]]): Which note types to load. See
-#             `get_all_valid_note_types()` for a list of valid note types.
-#         featurizer (str): Which featurizer to use. Either 'tf-idf', 'huggingface', or None
-#         n_rows (Optional[int], optional): Number of rows to load. Defaults to None.
-#         featurizer_kwargs (Optional[dict], optional): Keyword arguments passed to
-#             the featurizer. Defaults to None.
-
-#     Returns:
-#         pd.DataFrame: (Featurized) notes
-#     """
-#     return load_and_featurize_notes(
-#         note_names,
-#         featurizer=featurizer,
-#         n_rows=n_rows,
-#         featurizer_kwargs=featurizer_kwargs,
-#     )
-
-
-# @data_loaders.register("synth_notes")
-# def load_synth_notes(featurizer: str, **featurizer_kwargs) -> pd.DataFrame:
-#     """Load (featurized) synthetic notes for testing.
-
-#     Args:
-#         featurizer (str): Which featurizer to use
-#         **featurizer_kwargs: Keyword arguments passed to the featurizer
-
-#     Raises:
-#         ValueError: If given invalid featurizer
-
-#     Returns:
-#         pd.DataFrame: (Featurized) synthetic notes
-#     """
-#     p = PROJECT_ROOT / "tests" / "test_data"
-#     df = pd.read_csv(
-#         p / "raw" / "synth_txt_data.csv",
-#     ).drop("Unnamed: 0", axis=1)
-#     df = df.dropna()
-#     df["timestamp"] = pd.to_datetime(df["timestamp"])
-
-#     if featurizer == "tfidf":
-#         return _tfidf_featurize(
-#             df,
-#             tfidf_path=p / "test_tfidf" / "tfidf_10.pkl",
-#         )
-#     elif featurizer == "huggingface":
-#         return _huggingface_featurize(
-#             df,
-#             **featurizer_kwargs,
-#         )
-
-#     raise ValueError("Only tfidf or huggingface featurizer supported for synth notes")
diff --git a/src/timeseriesflattener/loaders/raw/load_visits.py b/src/timeseriesflattener/loaders/raw/load_visits.py
deleted file mode 100644
index 3d9797a..0000000
--- a/src/timeseriesflattener/loaders/raw/load_visits.py
+++ /dev/null
@@ -1,105 +0,0 @@
-"""Loaders for visits to psychiatry."""
-
-from typing import Optional
-
-import pandas as pd
-from wasabi import msg
-
-from psycop_feature_generation.loaders.raw.sql_load import sql_load
-from psycop_feature_generation.utils import data_loaders
-
-
-@data_loaders.register("physical_visits")
-def physical_visits(
-    shak_code: Optional[int] = None,
-    shak_sql_operator: Optional[str] = "=",
-    where_clause: Optional[str] = None,
-    where_separator: Optional[str] = "AND",
-    n_rows: Optional[int] = None,
-) -> pd.DataFrame:
-    """Load pshysical visits to both somatic and psychiatry.
-
-    Args:
-        shak_code (Optional[int], optional): SHAK code indicating where to keep/not keep visits from (e.g. 6600). Combines with
-            shak_sql_operator, e.g. "!= 6600". Defaults to None, in which case all admissions are kept.
-        shak_sql_operator (Optional[str], optional): Operator to use with shak_code. Defaults to "=".
-        where_clause (Optional[str], optional): Extra where-clauses to add to the SQL call. E.g. dw_ek_borger = 1. Defaults to None. # noqa: DAR102
-        where_separator (Optional[str], optional): Separator between where-clauses. Defaults to "AND".
-        n_rows (Optional[int], optional): Number of rows to return. Defaults to None.
-
-    Returns:
-        pd.DataFrame: Dataframe with all physical visits to psychiatry. Has columns dw_ek_borger and timestamp.
-    """
-
-    # SHAK = 6600 ≈ in psychiatry
-    d = {
-        "LPR3": {
-            "view": "[FOR_LPR3kontakter_psyk_somatik_inkl_2021_feb2022]",
-            "datetime_col": "datotid_lpr3kontaktstart",
-            "location_col": "shakkode_lpr3kontaktansvarlig",
-            "where": "AND pt_type in ('Ambulant', 'Akut ambulant', 'Indlæggelse')",
-        },
-        "LPR2_outpatient": {
-            "view": "[FOR_besoeg_psyk_somatik_LPR2_inkl_2021_feb2022]",
-            "datetime_col": "datotid_start",
-            "location_col": "shakafskode",
-            "where": "AND psykambbesoeg = 1",
-        },
-        "LPR2_acute_outpatient": {
-            "view": "[FOR_akutambulantekontakter_psyk_somatik_LPR2_inkl_2021_feb2022]",
-            "datetime_col": "datotid_start",
-            "location_col": "afsnit_stam",
-            "where": "",
-        },
-        "LPR2_admissions": {
-            "view": "[FOR_indlaeggelser_psyk_somatik_LPR2_inkl_2021_feb2022]",
-            "datetime_col": "datotid_indlaeggelse",
-            "location_col": "shakKode_kontaktansvarlig",
-            "where": "",
-        },
-    }
-
-    dfs = []
-
-    for meta in d.values():
-        cols = f"{meta['datetime_col']}, dw_ek_borger"
-
-        sql = f"SELECT {cols} FROM [fct].{meta['view']} WHERE {meta['datetime_col']} IS NOT NULL {meta['where']}"
-
-        if shak_code is not None:
-            sql += f" AND left({meta['location_col']}, {len(str(shak_code))}) {shak_sql_operator} {str(shak_code)}"
-
-        if where_clause is not None:
-            sql += f" {where_separator} {where_clause}"
-
-        df = sql_load(sql, database="USR_PS_FORSK", chunksize=None, n_rows=n_rows)
-        df.rename(columns={meta["datetime_col"]: "timestamp"}, inplace=True)
-
-        dfs.append(df)
-
-    # Concat the list of dfs
-    output_df = pd.concat(dfs)
-
-    # 0,8% of visits are duplicates. Unsure if overlap between sources or errors in source data. Removing.
-    output_df = output_df.drop_duplicates(
-        subset=["timestamp", "dw_ek_borger"],
-        keep="first",
-    )
-
-    output_df["value"] = 1
-
-    msg.good("Loaded physical visits")
-
-    return output_df.reset_index(drop=True)
-
-
-@data_loaders.register("physical_visits_to_psychiatry")
-def physical_visits_to_psychiatry(n_rows: Optional[int] = None) -> pd.DataFrame:
-    """Load physical visits to psychiatry."""
-    return physical_visits(shak_code=6600, shak_sql_operator="=", n_rows=n_rows)
-
-
-@data_loaders.register("physical_visits_to_somatic")
-def physical_visits_to_somatic(n_rows: Optional[int] = None) -> pd.DataFrame:
-    """Load physical visits to somatic."""
-    return physical_visits(shak_code=6600, shak_sql_operator="!=", n_rows=n_rows)
diff --git a/src/timeseriesflattener/loaders/raw/sql_load.py b/src/timeseriesflattener/loaders/raw/sql_load.py
deleted file mode 100644
index 7c3c19b..0000000
--- a/src/timeseriesflattener/loaders/raw/sql_load.py
+++ /dev/null
@@ -1,71 +0,0 @@
-"""Utility functions for SQL loading."""
-
-import urllib
-import urllib.parse
-from collections.abc import Generator
-from typing import Optional, Union
-
-import pandas as pd
-from sqlalchemy import create_engine
-
-
-def sql_load(
-    query: str,
-    server: str = "BI-DPA-PROD",
-    database: str = "USR_PS_Forsk",
-    chunksize: Optional[int] = None,
-    format_timestamp_cols_to_datetime: Optional[bool] = True,
-    n_rows: Optional[int] = None,
-) -> Union[pd.DataFrame, Generator[pd.DataFrame, None, None]]:
-    """Function to load a SQL query. If chunksize is None, all data will be
-    loaded into memory. Otherwise, will stream the data in chunks of chunksize
-    as a generator.
-
-    Args:
-        query (str): The SQL query
-        server (str): The BI server
-        database (str): The BI database
-        chunksize (int, optional): Defaults to 1000.
-        format_timestamp_cols_to_datetime (bool, optional): Whether to format all
-            columns with "datotid" in their name as pandas datetime. Defaults to true.
-        n_rows (int, optional): Defaults to None. If specified, only returns the first n rows.
-
-    Returns:
-        Union[pd.DataFrame, Generator[pd.DataFrame]]: DataFrame or generator of DataFrames
-
-    Example:
-        # From USR_PS_Forsk
-        >>> view = "[FOR_SFI_fritekst_resultat_udfoert_i_psykiatrien_aendret_2011]"
-        >>> sql = "SELECT * FROM [fct]." + view
-        >>> df = sql_load(sql, chunksize = None)
-    """
-    driver = "SQL Server"
-    params = urllib.parse.quote(
-        f"DRIVER={driver};SERVER={server};DATABASE={database};Trusted_Connection=yes",
-    )
-
-    if n_rows:
-        query = query.replace("SELECT", f"SELECT TOP {n_rows} ")
-
-    engine = create_engine(f"mssql+pyodbc:///?odbc_connect={params}")
-
-    conn = engine.connect().execution_options(
-        stream_results=True,
-        fast_executemany=True,
-    )
-
-    df = pd.read_sql(query, conn, chunksize=chunksize)
-
-    if format_timestamp_cols_to_datetime:
-        datetime_col_names = [
-            colname
-            for colname in df.columns
-            if any(substr in colname.lower() for substr in ["datotid", "timestamp"])
-        ]
-
-        df[datetime_col_names] = df[datetime_col_names].apply(pd.to_datetime)
-
-    conn.close()
-    engine.dispose()
-
-    return df
diff --git a/src/timeseriesflattener/loaders/raw/t2d_loaders.py b/src/timeseriesflattener/loaders/raw/t2d_loaders.py
deleted file mode 100644
index bbbbfb9..0000000
--- a/src/timeseriesflattener/loaders/raw/t2d_loaders.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from psycopmlutils.sql.loader import sql_load
-
-from psycop_feature_generation.utils import data_loaders
-
-
-@data_loaders.register("timestamp_exclusion")
-def timestamp_exclusion():
-    """Loads timestamps for the broad definition of diabetes used for wash-in.
-
-    See R files for details.
-    """
-    timestamp_any_diabetes = sql_load(
-        query="SELECT * FROM [fct].[psycop_t2d_first_diabetes_any]",
-        format_timestamp_cols_to_datetime=False,
-    )[["dw_ek_borger", "datotid_first_diabetes_any"]]
-
-    timestamp_any_diabetes = timestamp_any_diabetes.rename(
-        columns={"datotid_first_diabetes_any": "timestamp"},
-    )
-
-    return timestamp_any_diabetes
diff --git a/src/timeseriesflattener/loaders/raw/utils.py b/src/timeseriesflattener/loaders/raw/utils.py
deleted file mode 100644
index 3ce7f09..0000000
--- a/src/timeseriesflattener/loaders/raw/utils.py
+++ /dev/null
@@ -1,155 +0,0 @@
-"""Example of."""
-
-from typing import Optional, Union
-
-import pandas as pd
-
-from psycop_feature_generation.loaders.raw.sql_load import sql_load
-
-
-def str_to_sql_match_logic(
-    code_to_match: str,
-    code_sql_col_name: str,
-    load_diagnoses: bool,
-    match_with_wildcard: bool,
-):
-    """Generate SQL match logic from a single string.
-
-    Args:
-        code_to_match (list[str]): List of strings to match.
-        code_sql_col_name (str): Name of the SQL column containing the codes.
-        load_diagnoses (bool): Whether to load diagnoses or medications. Determines the logic. See calling function for more.
-        match_with_wildcard (bool): Whether to match on icd_code* / atc_code* or only icd_code / atc_code.
-    """
-    base_query = f"lower({code_sql_col_name}) LIKE '%{code_to_match.lower()}"
-
-    if match_with_wildcard:
-        return f"{base_query}%'"
-
-    if load_diagnoses:
-        return f"{base_query}' OR {base_query}#%'"
-
-    return f"{base_query}'"
-
-
-
-def list_to_sql_logic(
-    codes_to_match: list[str],
-    code_sql_col_name: str,
-    load_diagnoses: bool,
-    match_with_wildcard: bool,
-):
-    """Generate SQL match logic from a list of strings.
-
-    Args:
-        codes_to_match (list[str]): List of strings to match.
-        code_sql_col_name (str): Name of the SQL column containing the codes.
-        load_diagnoses (bool): Whether to load diagnoses or medications. Determines the logic. See calling function for more.
-        match_with_wildcard (bool): Whether to match on icd_code* / atc_code* or only icd_code / atc_code.
-    """
-    match_col_sql_strings = []
-
-    for code_str in codes_to_match:
-        base_query = f"lower({code_sql_col_name}) LIKE '%{code_str.lower()}"
-
-        if match_with_wildcard:
-            match_col_sql_strings.append(
-                f"{base_query}%'",
-            )
-        else:
-            # If the string is at the end of diagnosegruppestreng, it doesn't end with a hashtag
-            match_col_sql_strings.append(f"{base_query}'")
-
-            if load_diagnoses:
-                # If the string is at the beginning of diagnosegruppestreng, it doesn't start with a hashtag
-                match_col_sql_strings.append(
-                    f"lower({code_sql_col_name}) LIKE '{code_str.lower()}#%'",
-                )
-
-    return " OR ".join(match_col_sql_strings)
-
-
-def load_from_codes(
-    codes_to_match: Union[list[str], str],
-    load_diagnoses: bool,
-    code_col_name: str,
-    source_timestamp_col_name: str,
-    view: str,
-    output_col_name: Optional[str] = None,
-    match_with_wildcard: bool = True,
-    n_rows: Optional[int] = None,
-    exclude_codes: Optional[list[str]] = None,
-) -> pd.DataFrame:
-    """Load the visits that have diagnoses that match icd_code or atc code from
-    the beginning of their adiagnosekode or atc code string. Aggregates all
-    that match.
-
-    Args:
-        codes_to_match (Union[list[str], str]): Substring(s) to match diagnoses or medications for.
-            Diagnoses: Matches any diagnoses, whether a-diagnosis, b-diagnosis.
-            Both: If a list is passed, will count as a match if any of the icd_codes or at codes in the list match.
-        load_diagnoses (bool): Determines which mathing logic is employed. If True, will load diagnoses. If False, will load medications.
-            Diagnoses must be able to split a string like this:
-                A:DF431#+:ALFC3#B:DF329
-            Which means that if match_with_wildcard is False, we must match on *icd_code# or *icd_code followed by nothing. If it's true, we can match on *icd_code*.
-        code_col_name (str): Name of column containing either diagnosis (icd) or medication (atc) codes.
-            Takes either 'diagnosegruppestreng' or 'atc' as input.
-        source_timestamp_col_name (str): Name of the timestamp column in the SQL
-            view.
-        view (str): Name of the SQL view to load from.
-        output_col_name (str, optional): Name of new column string. Defaults to
-            None.
-        match_with_wildcard (bool, optional): Whether to match on icd_code* / atc_code*.
-            Defaults to true.
-        n_rows: Number of rows to return. Defaults to None.
-        exclude_codes (list[str], optional): Drop rows if their code is in this list. Defaults to None.
-
-    Returns:
-        pd.DataFrame: A pandas dataframe with dw_ek_borger, timestamp and
-            output_col_name = 1
-    """
-    fct = f"[{view}]"
-
-    if isinstance(codes_to_match, list) and len(codes_to_match) > 1:
-        match_col_sql_str = list_to_sql_logic(
-            codes_to_match=codes_to_match,
-            code_sql_col_name=code_col_name,
-            load_diagnoses=load_diagnoses,
-            match_with_wildcard=match_with_wildcard,
-        )
-    elif isinstance(codes_to_match, str):
-        match_col_sql_str = str_to_sql_match_logic(
-            code_to_match=codes_to_match,
-            code_sql_col_name=code_col_name,
-            load_diagnoses=load_diagnoses,
-            match_with_wildcard=match_with_wildcard,
-        )
-    else:
-        raise ValueError("codes_to_match must be either a list or a string.")
-
-    sql = (
-        f"SELECT dw_ek_borger, {source_timestamp_col_name}, {code_col_name}"
-        + f" FROM [fct].{fct} WHERE {source_timestamp_col_name} IS NOT NULL AND ({match_col_sql_str})"
-    )
-
-    df = sql_load(sql, database="USR_PS_FORSK", chunksize=None, n_rows=n_rows)
-
-    if exclude_codes:
-        # Drop all rows whose code_col_name is in exclude_codes
-        df = df[~df[code_col_name].isin(exclude_codes)]
-
-    if output_col_name is None:
-        if isinstance(codes_to_match, list):
-            output_col_name = "_".join(codes_to_match)
-        else:
-            output_col_name = codes_to_match
-
-    df[output_col_name] = 1
-
-    df.drop([f"{code_col_name}"], axis="columns", inplace=True)
-
-    return df.rename(
-        columns={
-            source_timestamp_col_name: "timestamp",
-        },
-    )
diff --git a/src/timeseriesflattener/loaders/utils.py b/src/timeseriesflattener/loaders/utils.py
deleted file mode 100644
index d79abb4..0000000
--- a/src/timeseriesflattener/loaders/utils.py
+++ /dev/null
@@ -1,18 +0,0 @@
-"""Example of how to get tfidf vocab."""
-
-from psycop_feature_generation.utils import FEATURIZERS_PATH
-
-# pylint: disable=missing-function-docstring
-
-
-def get_tfidf_vocab(
-    n_features: int,
-) -> list[str]:  # pylint: disable=missing-function-docstring
-    with open(  # pylint: disable=unspecified-encoding
-        FEATURIZERS_PATH / f"tfidf_{str(n_features)}.txt",
-        "r",
-    ) as f:
-        return f.read().splitlines()
-
-
-TFIDF_VOCAB = {n: get_tfidf_vocab(n) for n in [100, 500, 1000]}
diff --git a/src/timeseriesflattener/timeseriesflattener/resolve_multiple_functions.py b/src/timeseriesflattener/resolve_multiple_functions.py
similarity index 100%
rename from src/timeseriesflattener/timeseriesflattener/resolve_multiple_functions.py
rename to src/timeseriesflattener/resolve_multiple_functions.py
diff --git a/src/timeseriesflattener/timeseriesflattener/__init__.py b/src/timeseriesflattener/timeseriesflattener/__init__.py
deleted file mode 100644
index c4eae1f..0000000
--- a/src/timeseriesflattener/timeseriesflattener/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-"""Init timeseriesflattener."""
-from .flattened_dataset import FlattenedDataset
diff --git a/src/timeseriesflattener/utils.py b/src/timeseriesflattener/utils.py
index 727bf43..8d3ab68 100644
--- a/src/timeseriesflattener/utils.py
+++ b/src/timeseriesflattener/utils.py
@@ -6,7 +6,7 @@ utilities. If this file grows, consider splitting it up.
 import os
 from collections.abc import Hashable
 from pathlib import Path
-from typing import Any, Optional, Union
+from typing import Any, Optional
 
 import catalogue
 import pandas as pd


Test patch:
diff --git a/src/timeseriesflattener/utils_for_testing.py b/src/timeseriesflattener/utils_for_testing.py
index 8a5063e..bb6d2ad 100644
--- a/src/timeseriesflattener/utils_for_testing.py
+++ b/src/timeseriesflattener/utils_for_testing.py
@@ -10,22 +10,21 @@ import pytest
 from pandas import DataFrame
 from pandas.testing import assert_series_equal
 
-from psycop_feature_generation.loaders.synth.raw.load_synth_data import (
+from loaders.synth.raw.load_synth_data import (
     load_synth_outcome,
     load_synth_prediction_times,
 )
-from psycop_feature_generation.timeseriesflattener import FlattenedDataset
-from psycop_feature_generation.timeseriesflattener.feature_spec_objects import (
-    TemporalSpec,
-)
-from psycop_feature_generation.utils import data_loaders
+from timeseriesflattener import FlattenedDataset
+from timeseriesflattener.feature_spec_objects import TemporalSpec
+from timeseriesflattener.utils import data_loaders
 
 
 def convert_cols_with_matching_colnames_to_datetime(
     df: DataFrame,
     colname_substr: str,
 ) -> DataFrame:
-    """Convert columns that contain colname_substr in their name to datetimes
+    """Convert columns that contain colname_substr in their name to datetimes.
+
     Args:
         df (DataFrame): The df to convert. # noqa: DAR101
         colname_substr (str): Substring to match on. # noqa: DAR101
@@ -82,7 +81,8 @@ def assert_flattened_data_as_expected(
     expected_df: Optional[pd.DataFrame] = None,
     expected_values: Optional[Sequence[Any]] = None,
 ):
-    """Take a prediction times df and output spec and assert that the flattened data is as expected."""
+    """Take a prediction times df and output spec and assert that the flattened
+    data is as expected."""
     if isinstance(prediction_times_df, str):
         prediction_times_df = str_to_df(prediction_times_df)
 
diff --git a/tests/conftest.py b/tests/conftest.py
index b43d4eb..389e7fe 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,8 +1,5 @@
 # pylint: disable-all
 
-import os
-import sys
-
 import pytest
 
 
diff --git a/tests/test_check_raw_df/test_check_raw_df.py b/tests/test_check_raw_df/test_check_raw_df.py
index 65e9cb1..08cce0c 100644
--- a/tests/test_check_raw_df/test_check_raw_df.py
+++ b/tests/test_check_raw_df/test_check_raw_df.py
@@ -2,8 +2,8 @@
 
 import pytest
 
-from psycop_feature_generation.data_checks.raw.check_raw_df import check_raw_df
-from psycop_feature_generation.utils_for_testing import (  # noqa pylint: disable=import-error
+from data_checks.raw.check_raw_df import check_raw_df
+from timeseriesflattener.utils_for_testing import (  # noqa pylint: disable=import-error
     str_to_df,
 )
 
diff --git a/tests/test_data/raw/create_synth_prediction_times.py b/tests/test_data/raw/create_synth_prediction_times.py
index 727dd07..5c13cbb 100644
--- a/tests/test_data/raw/create_synth_prediction_times.py
+++ b/tests/test_data/raw/create_synth_prediction_times.py
@@ -4,7 +4,7 @@ from psycopmlutils.synth_data_generator.synth_col_generators import (
     generate_data_columns,
 )
 
-from psycop_feature_generation.utils import PROJECT_ROOT
+from timeseriesflattener.utils import PROJECT_ROOT
 
 if __name__ == "__main__":
     # Get project root directory
diff --git a/tests/test_data/raw/create_synth_raw_float.py b/tests/test_data/raw/create_synth_raw_float.py
index fa652d1..6f8bea0 100644
--- a/tests/test_data/raw/create_synth_raw_float.py
+++ b/tests/test_data/raw/create_synth_raw_float.py
@@ -4,7 +4,7 @@ from psycopmlutils.synth_data_generator.synth_col_generators import (
     generate_data_columns,
 )
 
-from psycop_feature_generation.utils import PROJECT_ROOT
+from timeseriesflattener.utils import PROJECT_ROOT
 
 if __name__ == "__main__":
     # Get project root directory
diff --git a/tests/test_feature_describer/test_feature_describer.py b/tests/test_feature_describer/test_feature_describer.py
index 61e57e7..9b37ce8 100644
--- a/tests/test_feature_describer/test_feature_describer.py
+++ b/tests/test_feature_describer/test_feature_describer.py
@@ -3,21 +3,18 @@ import numpy as np
 import pandas as pd
 import pytest
 
-from psycop_feature_generation.data_checks.flattened.feature_describer import (
+from data_checks.flattened.feature_describer import (
     generate_feature_description_df,
     generate_feature_description_row,
 )
-from psycop_feature_generation.timeseriesflattener.feature_spec_objects import (
-    PredictorSpec,
-    StaticSpec,
-)
-from psycop_feature_generation.utils import PROJECT_ROOT
+from timeseriesflattener.feature_spec_objects import AnySpec, PredictorSpec, StaticSpec
+from timeseriesflattener.utils import PROJECT_ROOT
 
 # pylint: disable=redefined-outer-name, missing-function-docstring
 
 
 @pytest.fixture()
-def predictor_specs(df):
+def predictor_specs():
     return [
         PredictorSpec(
             values_df=pd.DataFrame({"hba1c": [0]}),
@@ -30,7 +27,7 @@ def predictor_specs(df):
 
 
 @pytest.fixture()
-def static_spec(df):
+def static_spec():
     return [
         StaticSpec(
             values_df=pd.DataFrame({"hba1c": [0]}),
@@ -56,7 +53,7 @@ def test_load_dataset(df):
 
 def test_generate_feature_description_row_for_temporal_spec(
     df: pd.DataFrame,
-    predictor_specs: list[PredictorSpec],
+    predictor_specs: list[AnySpec],
 ):
     spec = predictor_specs[0]
 
diff --git a/tests/test_loaders/test_non_numerical_coercion.py b/tests/test_loaders/test_non_numerical_coercion.py
deleted file mode 100644
index 39ee489..0000000
--- a/tests/test_loaders/test_non_numerical_coercion.py
+++ /dev/null
@@ -1,40 +0,0 @@
-"""Tests of coercion from strings to numerical."""
-
-import pandas as pd
-
-from psycop_feature_generation.loaders.non_numerical_coercer import (
-    multiply_inequalities_in_df,
-)
-from psycop_feature_generation.utils_for_testing import (
-    str_to_df,  # pylint: disable=import-error
-)
-
-# pylint: disable=missing-function-docstring
-
-
-def test_non_numerical_coercion():
-    df_str = """dw_ek_borger,timestamp,value
-                1,2021-12-31 00:00:01,>90
-                2,2021-12-31 00:00:01,>=90
-                3,2021-12-31 00:00:01,<90
-                4,2021-12-31 00:00:01,<=90
-                5,2021-12-31 00:00:01,"<1,2"
-                6,2021-12-31 00:00:01,">90.0. Med forbehold - tidsfrist overskredet med 1 time."
-            """
-
-    expected_df_str = """dw_ek_borger,timestamp,value
-                1,2021-12-31 00:00:01,135.0
-                2,2021-12-31 00:00:01,108.0
-                3,2021-12-31 00:00:01,60.3
-                4,2021-12-31 00:00:01,72.0
-                5,2021-12-31 00:00:01,0.804
-                6,2021-12-31 00:00:01,135.0
-            """
-
-    df = str_to_df(df_str, convert_str_to_float=False)
-    expected_df = str_to_df(expected_df_str, convert_str_to_float=False)
-
-    df = multiply_inequalities_in_df(df)
-
-    for col in df.columns:
-        pd.testing.assert_series_equal(df[col], expected_df[col], check_dtype=False)
diff --git a/tests/test_timeseriesflattener/test_add_values.py b/tests/test_timeseriesflattener/test_add_values.py
index 23e7744..a5f35cc 100644
--- a/tests/test_timeseriesflattener/test_add_values.py
+++ b/tests/test_timeseriesflattener/test_add_values.py
@@ -6,17 +6,9 @@ import numpy as np
 import pandas as pd
 import pytest
 
-from psycop_feature_generation.loaders.raw.load_text import (  # noqa pylint: disable=unused-import; load_synth_notes,
-    _chunk_text,
-)
-from psycop_feature_generation.timeseriesflattener import FlattenedDataset
-from psycop_feature_generation.timeseriesflattener.feature_spec_objects import (
-    AnySpec,
-    OutcomeSpec,
-    PredictorGroupSpec,
-    PredictorSpec,
-)
-from psycop_feature_generation.utils_for_testing import (
+from timeseriesflattener import FlattenedDataset
+from timeseriesflattener.feature_spec_objects import AnySpec, OutcomeSpec, PredictorSpec
+from timeseriesflattener.utils_for_testing import (
     assert_flattened_data_as_expected,
     str_to_df,
 )
@@ -543,100 +535,3 @@ def test_add_temporal_incident_binary_outcome():
             if df[col].dtype == "int64":
                 df[col] = df[col].astype("int32")
         pd.testing.assert_series_equal(outcome_df[col], expected_df[col])
-
-
-# def test_add_tfidf_text_data():
-#     prediction_times_str = """dw_ek_borger,timestamp,
-#                             746430.0,1970-05-01 00:00:00
-#                             765709.0,1971-05-14 22:04:00
-#                             """
-
-#     prediction_times_df = str_to_df(prediction_times_str)
-
-#     flattened_dataset = FlattenedDataset(
-#         prediction_times_df=prediction_times_df,
-#         timestamp_col_name="timestamp",
-#         id_col_name="dw_ek_borger",
-#         n_workers=4,
-#     )
-
-#     synth_notes_df = data_loaders.get_all()["synth_notes"](featurizer="tfidf")
-
-#     predictor_specs = PredictorGroupSpec(
-#         df=[synth_notes_df],
-#         interval_days=[1, 365, 720],
-#         resolve_multiple_fn=["min"],
-#         fallback=[np.nan],
-#         allowed_nan_value_prop=[0],
-#         loader_kwargs=[{"featurizer": "tfidf"}],
-#         feature_name="tfidf",
-#     ).create_combinations()
-
-#     flattened_dataset.add_temporal_predictors_from_pred_specs(
-#         predictor_specs=predictor_specs,
-#     )
-
-#     outcome_df = flattened_dataset.df
-
-#     assert outcome_df.shape == (2, 33)
-
-#     # 20 nas = 2 ids * 10 predictors with lookbehind 1 day. First get sum of each column. Then get sum of the row.
-#     assert outcome_df.isna().sum().sum() == 20
-
-#     # assert len()
-
-
-# @pytest.mark.slow  # Only run if --runslow is passed to pytest
-# def test_add_hf_text_data():
-#     prediction_times_str = """dw_ek_borger,timestamp,
-#                             746430.0,1970-05-01 00:00:00
-#                             765709.0,1971-05-14 22:04:00
-#                             """
-
-#     prediction_times_df = str_to_df(prediction_times_str)
-
-#     flattened_dataset = FlattenedDataset(
-#         prediction_times_df=prediction_times_df,
-#         timestamp_col_name="timestamp",
-#         id_col_name="dw_ek_borger",
-#         n_workers=4,
-#     )
-
-#     predictor_list = create_feature_combinations(
-#         [
-#             {
-#                 "predictor_df": "synth_notes",
-#                 "lookbehind_days": [1, 365, 720],
-#                 "resolve_multiple_fn": "min",
-#                 "fallback": np.nan,
-#                 "loader_kwargs": {
-#                     "featurizer": "huggingface",
-#                     "model_id": "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
-#                 },
-#                 "new_col_name": [TEST_HF_EMBEDDINGS],
-#             },
-#         ],
-#     )
-
-#     flattened_dataset.add_temporal_predictors_from_list_of_argument_dictionaries(
-#         predictors=predictor_list,
-#     )
-
-#     outcome_df = flattened_dataset.df
-
-#     assert outcome_df.shape == (2, 1155)
-
-#     # 768 nas = 2 ids * 384 predictors with lookbehind 1 day. First get sum of each column. Then get sum of the row.
-#     assert outcome_df.isna().sum().sum() == 768
-
-
-def test_chunk_text():
-    text = "This is a test. This is another test. This is a third test. This is a fourth test."
-    expected = [
-        "This is a test.",
-        "This is another test.",
-        "This is a third",
-        "test. This is a",
-    ]
-
-    assert _chunk_text(text, 4) == expected
diff --git a/tests/test_timeseriesflattener/test_create_feature_combinations.py b/tests/test_timeseriesflattener/test_create_feature_combinations.py
index ec60ddd..7f4d141 100644
--- a/tests/test_timeseriesflattener/test_create_feature_combinations.py
+++ b/tests/test_timeseriesflattener/test_create_feature_combinations.py
@@ -2,15 +2,11 @@
 
 # pylint: disable=missing-function-docstring
 
-from psycop_feature_generation.loaders.synth.raw.load_synth_data import (  # pylint: disable=unused-import
+from loaders.synth.raw.load_synth_data import (  # pylint: disable=unused-import
     synth_predictor_float,
 )
-from psycop_feature_generation.timeseriesflattener.feature_spec_objects import (
-    PredictorGroupSpec,
-)
-from psycop_feature_generation.utils import (  # pylint: disable=unused-import
-    data_loaders,
-)
+from timeseriesflattener.feature_spec_objects import PredictorGroupSpec
+from timeseriesflattener.utils import data_loaders  # pylint: disable=unused-import
 
 
 def test_skip_all_if_no_need_to_process():
diff --git a/tests/test_timeseriesflattener/test_errors.py b/tests/test_timeseriesflattener/test_errors.py
index 0c1bf41..9cc818b 100644
--- a/tests/test_timeseriesflattener/test_errors.py
+++ b/tests/test_timeseriesflattener/test_errors.py
@@ -2,13 +2,9 @@
 
 import pytest
 
-from psycop_feature_generation.timeseriesflattener.feature_spec_objects import (
-    PredictorSpec,
-)
-from psycop_feature_generation.timeseriesflattener.flattened_dataset import (
-    FlattenedDataset,
-)
-from psycop_feature_generation.utils_for_testing import (
+from timeseriesflattener.feature_spec_objects import PredictorSpec
+from timeseriesflattener.flattened_dataset import FlattenedDataset
+from timeseriesflattener.utils_for_testing import (
     str_to_df,  # pylint: disable=import-error
 )
 
diff --git a/tests/test_timeseriesflattener/test_feature_spec_objects.py b/tests/test_timeseriesflattener/test_feature_spec_objects.py
index 4c0fe29..f95fc56 100644
--- a/tests/test_timeseriesflattener/test_feature_spec_objects.py
+++ b/tests/test_timeseriesflattener/test_feature_spec_objects.py
@@ -2,10 +2,10 @@
 import pandas as pd
 import pytest
 
-from psycop_feature_generation.loaders.synth.raw.load_synth_data import (  # pylint: disable=unused-import
+from loaders.synth.raw.load_synth_data import (  # pylint: disable=unused-import
     synth_predictor_float,
 )
-from psycop_feature_generation.timeseriesflattener.feature_spec_objects import AnySpec
+from timeseriesflattener.feature_spec_objects import AnySpec
 
 
 def test_anyspec_init():
@@ -22,6 +22,7 @@ def test_anyspec_init():
 
 
 def test_loader_kwargs():
+    """Test that loader kwargs are passed correctly."""
     spec = AnySpec(
         values_loader="synth_predictor_float",
         prefix="test",
@@ -32,9 +33,7 @@ def test_loader_kwargs():
 
 
 def test_anyspec_incorrect_values_loader_str():
+    """Test that AnySpec raises an error if the values loader is not a key in
+    the loader registry."""
     with pytest.raises(ValueError, match=r".*in registry.*"):
         AnySpec(values_loader="I don't exist", prefix="test")
-
-
-if __name__ == "__main__":
-    test_anyspec_output_col_name_override()
diff --git a/tests/test_timeseriesflattener/test_flattened_dataset_generation.py b/tests/test_timeseriesflattener/test_flattened_dataset_generation.py
index 2a70337..e162e8a 100644
--- a/tests/test_timeseriesflattener/test_flattened_dataset_generation.py
+++ b/tests/test_timeseriesflattener/test_flattened_dataset_generation.py
@@ -3,33 +3,25 @@
 # pylint: disable=unused-import, redefined-outer-name
 
 from pathlib import Path
-from typing import Iterable
+from typing import Iterable, List
 
 import numpy as np
 import pandas as pd
 import pytest
 
-from application.t2d.generate_features_and_write_to_disk import (
-    save_feature_set_description_to_disk,
-    split_and_save_dataset_to_disk,
-)
-from psycop_feature_generation.loaders.synth.raw.load_synth_data import (
+from loaders.synth.raw.load_synth_data import (
     load_synth_prediction_times,
     synth_predictor_binary,
     synth_predictor_float,
 )
-from psycop_feature_generation.timeseriesflattener.feature_spec_objects import (
+from timeseriesflattener.feature_spec_objects import (
     OutcomeSpec,
     PredictorGroupSpec,
+    PredictorSpec,
     TemporalSpec,
 )
-from psycop_feature_generation.timeseriesflattener.flattened_dataset import (
-    FlattenedDataset,
-)
-from psycop_feature_generation.utils_for_testing import (
-    synth_outcome,
-    synth_prediction_times,
-)
+from timeseriesflattener.flattened_dataset import FlattenedDataset
+from timeseriesflattener.utils_for_testing import synth_outcome, synth_prediction_times
 
 base_float_predictor_combinations = PredictorGroupSpec(
     values_loader=["synth_predictor_float"],
@@ -95,7 +87,7 @@ def check_dfs_have_same_contents_by_column(df1, df2):
 
 def create_flattened_df(
     cache_dir: Path,
-    predictor_specs: Iterable[TemporalSpec],
+    predictor_specs: list[PredictorSpec],
     prediction_times_df: pd.DataFrame,
 ):
     """Create a dataset df for testing."""
@@ -121,6 +113,7 @@ def test_cache_hitting(
     synth_prediction_times,
     predictor_specs,
 ):
+    """Test that cache hits."""
 
     # Create the cache
     first_df = create_flattened_df(
@@ -144,78 +137,6 @@ def test_cache_hitting(
     assert len(list(tmp_path.glob("*"))) == len(predictor_specs)
 
 
-@pytest.mark.parametrize(
-    "predictor_combinations",
-    [base_float_predictor_combinations, base_binary_predictor_combinations],
-)
-def test_all_non_online_elements_in_pipeline(
-    tmp_path,
-    synth_prediction_times,
-    synth_outcome,
-    predictor_combinations,
-):
-    """Test that the splitting and saving to disk works as expected."""
-
-    flattened_ds = FlattenedDataset(
-        prediction_times_df=synth_prediction_times,
-        n_workers=4,
-        feature_cache_dir=None,
-    )
-
-    flattened_ds.add_temporal_predictors_from_pred_specs(
-        predictor_combinations,
-    )
-
-    flattened_ds.add_temporal_outcome(
-        output_spec=OutcomeSpec(
-            values_df=synth_outcome,
-            interval_days=365,
-            resolve_multiple_fn="max",
-            fallback=0,
-            incident=True,
-            feature_name="value",
-        ),
-    )
-
-    flattened_df = flattened_ds.df
-
-    split_ids = {}
-
-    start_idx = 0
-
-    # Get the first 20% of the IDs
-    splits = ["train", "test", "val"]
-
-    for split in splits:
-        prop_per_split = 0.2
-        end_idx = int(start_idx + len(flattened_df) * prop_per_split)
-
-        # Get 20% of the dataframe
-        ids = flattened_df.iloc[start_idx:end_idx]
-
-        split_ids[split] = ids
-
-        start_idx = end_idx
-
-    split_and_save_dataset_to_disk(
-        flattened_df=flattened_df,
-        out_dir=tmp_path,
-        file_prefix="integration",
-        split_ids_dict=split_ids,
-        splits=splits,
-        file_suffix="parquet",
-    )
-
-    save_feature_set_description_to_disk(
-        predictor_specs=predictor_combinations,
-        flattened_dataset_file_dir=tmp_path,
-        out_dir=tmp_path,
-        file_suffix="parquet",
-        describe_splits=True,
-        compare_splits=True,
-    )
-
-
 if __name__ == "__main__":
     base_float_predictor_combinations = PredictorGroupSpec(
         values_loader=["synth_predictor_float"],
diff --git a/tests/test_timeseriesflattener/test_resolve_multiple.py b/tests/test_timeseriesflattener/test_resolve_multiple.py
index 39f3302..9bfa131 100644
--- a/tests/test_timeseriesflattener/test_resolve_multiple.py
+++ b/tests/test_timeseriesflattener/test_resolve_multiple.py
@@ -3,18 +3,15 @@
 
 import numpy as np
 
-from psycop_feature_generation.timeseriesflattener.feature_spec_objects import (
-    OutcomeSpec,
-    PredictorSpec,
-)
-from psycop_feature_generation.timeseriesflattener.resolve_multiple_functions import (  # noqa pylint: disable=unused-import
+from timeseriesflattener.feature_spec_objects import OutcomeSpec, PredictorSpec
+from timeseriesflattener.resolve_multiple_functions import (  # noqa pylint: disable=unused-import
     earliest,
     latest,
     maximum,
     mean,
     minimum,
 )
-from psycop_feature_generation.utils_for_testing import (
+from timeseriesflattener.utils_for_testing import (
     assert_flattened_data_as_expected,
     str_to_df,
 )