|pypi| |actions| |codecov| |downloads|
edc-randomization
=================
Randomization objects for clinicedc projects
Overview
++++++++
The ``Randomizer`` class emulates the randomization of a clincial trial participant in
realtime. This module doesn't actually `randomize` in realtime. Instead, a CSV file is
prepared in advance by the statistician. This CSV file lists the order in which subjects
are to be randomized. The ``Randomizer`` class initially imports the entire list in order
into a ``model``. When a subject is to be randomized, the ``Randomizer`` class selects
the next available row from the model.
A very basic ``randomization_list.csv`` prepared in advance might look like this::
site_name,sid,assignment
temeke,1000,active
temeke,1001,active
temeke,1002,placebo
temeke,1003,active
temeke,1004,placebo
temeke,1005,placebo
...
For large multisite trials this may be thousands of lines ordered using some type of block
randomization.
This module will import (only once) all rows from the CSV file into a model. The ``Randomizer``
class selects and allocates in order by site_name one row per participant from the model.
.. code-block:: python
randomizer_cls = site_randomizers.get("default")
randomizer_cls.randomize(subject_identifier=subject_identifier, ...)
# or just:
site_randomizers.randomize("default", subject_identifier=subject_identifier, ...)
Usually, the ``Randomizer`` class is instantiated in a ``signal`` once the subject's
eligibility is confirmed and the subject's informed consent is submitted. A
`signal` attached to the subject's informed consent is a good place to do this assuming the sequence
of events are 1) pass eligibility criteria, 2) complete informed consent, 3) `randomize` and
issue study identifier 4) start baseline visit.
.. code-block:: python
@receiver(
post_save,
weak=False,
sender=SubjectConsent,
dispatch_uid="subject_consent_on_post_save",
)
def subject_consent_on_post_save(sender, instance, raw, created, **kwargs):
if not raw:
if created:
...
# randomize
site_randomizers.randomize(
"default",
subject_identifier=instance.subject_identifier,
report_datetime=instance.consent_datetime,
site=instance.site,
user=instance.user_created,
)
...
Registering a randomizer
++++++++++++++++++++++++
The default ``Randomizer`` class is ``edc_randomization.randomizer.Randomizer``. Unless you
indicate otherwise, it will be automatically registered with the site controller,
``site_randomizers`` with the name ``default``. It is recommended you access the ``Randomizer``
class through ``site_randomizers`` instead of directly importing.
.. code-block:: python
randomizer_cls = site_randomizers.get("default")
Customizing the default randomizer
++++++++++++++++++++++++++++++++++
Some attributes of the default ``Randomizer`` class can be customized using ``settings`` attributes:
.. code-block:: python
EDC_RANDOMIZATION_LIST_PATH = 'path/to/csv_file'
EDC_RANDOMIZATION_ASSIGNMENT_MAP = {
"intervention": 1,
"control": 2,
}
EDC_RANDOMIZATION_ASSIGNMENT_DESCRIPTION_MAP = {
"intervention": "Fluconazole plus flucytosine",
"control": "Fluconazole"
}
Creating a custom randomizer
++++++++++++++++++++++++++++
If you need to customize further, create a custom ``Randomizer`` class.
In the example below, ``gender`` is added for a trial stratified by ``gender``.
Custom ``Randomizer`` classes live in ``randomizers.py`` in the root of your app. The
``site_randomizers`` controller will ``autodiscover`` them.
.. code-block:: python
# my_app/randomizers.py
@register()
class MyRandomizer(Randomizer):
name = "my_randomizer"
model = "edc_randomization.myrandomizationlist"
randomization_list_path = tmpdir
assignment_map = {"Intervention": 1, "Control": 0}
assignment_description_map = {"Intervention": "Fluconazole plus flucytosine", "Control": "Fluconazole"}
extra_csv_fieldnames = ["gender"]
def __init__(self, gender=None, **kwargs):
self.gender = gender
super().__init__(**kwargs)
@property
def extra_required_instance_attrs(self):
return dict(gender=self.gender)
@property
def extra_model_obj_options(self):
return dict(gender=self.gender)
@classmethod
def get_extra_list_display(cls):
return [(4, "gender")]
The ``register()`` decorator registers the custom class with ``site_randomizers``.
With a custom randomizer, the default ``Randomizer`` class is no longer needed,
update settings to prevent the default class from registering.
Use the settings attribute:
.. code-block:: python
EDC_RANDOMIZATION_REGISTER_DEFAULT_RANDOMIZER = False
Confirm this by checking the ``site_randomizers``:
.. code-block:: python
>>> randomizer_cls = site_randomizers.get("default")
NotRegistered: A Randomizer class by this name ...
>>> randomizer_cls = site_randomizers.get("my_randomizer")
>>> randomizer_cls.name
"my_randomizer"
Manually Importing from CSV
+++++++++++++++++++++++++++
A ``Randomizer`` class will call ``import_list`` when it is instantiated
for the first time. If you want to load the CSV file manually,
import the ``Randomizer`` class and call ``import_list()``.
.. code-block:: python
>>> randomizer_cls = site_randomizers.get("my_randomizer")
>>> randomizer_cls.import_list()
Import CSV data
Randomizer:
- Name: my_randomizer
- Assignments: {'active': 1, 'placebo': 2}
- Model: edc_randomization.myrandomizationlist
- Path: /home/me/.etc/randomization_list.csv
- Imported 5 SIDs for randomizer `my_randomizer` into model `edc_randomization.myrandomizationlist`
from /home/me/.etc/randomization_list.csv.
- Verified OK.
Manually Export to CSV
++++++++++++++++++++++
.. code-block:: python
>>> from edc_randomization.utils import export_randomization_list
>>> export_randomization_list(randomizer_name="default",path="~/", username="erikvw")
If the user does not have permissions to view the randomizationlist table, a ``RandomizationListExporterError`` will be raised:
.. code-block:: python
RandomizationListExporterError: User `erikvw` does not have permission to view 'edc_randomization.randomizationlist'
.. |pypi| image:: https://img.shields.io/pypi/v/edc-randomization.svg
:target: https://pypi.python.org/pypi/edc-randomization
.. |actions| image:: https://github.com/clinicedc/edc-randomization/actions/workflows/build.yml/badge.svg
:target: https://github.com/clinicedc/edc-randomization/actions/workflows/build.yml
.. |codecov| image:: https://codecov.io/gh/clinicedc/edc-randomization/branch/develop/graph/badge.svg
:target: https://codecov.io/gh/clinicedc/edc-randomization
.. |downloads| image:: https://pepy.tech/badge/edc-randomization
:target: https://pepy.tech/project/edc-randomization
Raw data
{
"_id": null,
"home_page": "https://github.com/clinicedc/edc-randomization",
"name": "edc-randomization",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": "django Edc randomization, clinicedc, clinical trials",
"author": "Erik van Widenfelt",
"author_email": "ew2789@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/2b/27/b848077c9a0f263433fc34aac1bde3fdb964a2e441c7fe0044dcbbd8be20/edc-randomization-0.3.56.tar.gz",
"platform": null,
"description": "|pypi| |actions| |codecov| |downloads|\n\nedc-randomization\n=================\n\nRandomization objects for clinicedc projects\n\nOverview\n++++++++\n\nThe ``Randomizer`` class emulates the randomization of a clincial trial participant in\nrealtime. This module doesn't actually `randomize` in realtime. Instead, a CSV file is\nprepared in advance by the statistician. This CSV file lists the order in which subjects\nare to be randomized. The ``Randomizer`` class initially imports the entire list in order\ninto a ``model``. When a subject is to be randomized, the ``Randomizer`` class selects\nthe next available row from the model.\n\nA very basic ``randomization_list.csv`` prepared in advance might look like this::\n\n site_name,sid,assignment\n temeke,1000,active\n temeke,1001,active\n temeke,1002,placebo\n temeke,1003,active\n temeke,1004,placebo\n temeke,1005,placebo\n ...\n\nFor large multisite trials this may be thousands of lines ordered using some type of block\nrandomization.\n\nThis module will import (only once) all rows from the CSV file into a model. The ``Randomizer``\nclass selects and allocates in order by site_name one row per participant from the model.\n\n.. code-block:: python\n\n randomizer_cls = site_randomizers.get(\"default\")\n randomizer_cls.randomize(subject_identifier=subject_identifier, ...)\n # or just:\n site_randomizers.randomize(\"default\", subject_identifier=subject_identifier, ...)\n\nUsually, the ``Randomizer`` class is instantiated in a ``signal`` once the subject's\neligibility is confirmed and the subject's informed consent is submitted. A\n`signal` attached to the subject's informed consent is a good place to do this assuming the sequence\nof events are 1) pass eligibility criteria, 2) complete informed consent, 3) `randomize` and\nissue study identifier 4) start baseline visit.\n\n.. code-block:: python\n\n @receiver(\n post_save,\n weak=False,\n sender=SubjectConsent,\n dispatch_uid=\"subject_consent_on_post_save\",\n )\n def subject_consent_on_post_save(sender, instance, raw, created, **kwargs):\n if not raw:\n if created:\n ...\n # randomize\n site_randomizers.randomize(\n \"default\",\n subject_identifier=instance.subject_identifier,\n report_datetime=instance.consent_datetime,\n site=instance.site,\n user=instance.user_created,\n )\n ...\n\n\nRegistering a randomizer\n++++++++++++++++++++++++\nThe default ``Randomizer`` class is ``edc_randomization.randomizer.Randomizer``. Unless you\nindicate otherwise, it will be automatically registered with the site controller,\n``site_randomizers`` with the name ``default``. It is recommended you access the ``Randomizer``\nclass through ``site_randomizers`` instead of directly importing.\n\n.. code-block:: python\n\n randomizer_cls = site_randomizers.get(\"default\")\n\n\nCustomizing the default randomizer\n++++++++++++++++++++++++++++++++++\n\nSome attributes of the default ``Randomizer`` class can be customized using ``settings`` attributes:\n\n.. code-block:: python\n\n EDC_RANDOMIZATION_LIST_PATH = 'path/to/csv_file'\n EDC_RANDOMIZATION_ASSIGNMENT_MAP = {\n \"intervention\": 1,\n \"control\": 2,\n }\n EDC_RANDOMIZATION_ASSIGNMENT_DESCRIPTION_MAP = {\n \"intervention\": \"Fluconazole plus flucytosine\",\n \"control\": \"Fluconazole\"\n }\n\nCreating a custom randomizer\n++++++++++++++++++++++++++++\n\nIf you need to customize further, create a custom ``Randomizer`` class.\n\nIn the example below, ``gender`` is added for a trial stratified by ``gender``.\n\nCustom ``Randomizer`` classes live in ``randomizers.py`` in the root of your app. The\n``site_randomizers`` controller will ``autodiscover`` them.\n\n.. code-block:: python\n\n # my_app/randomizers.py\n\n @register()\n class MyRandomizer(Randomizer):\n name = \"my_randomizer\"\n model = \"edc_randomization.myrandomizationlist\"\n randomization_list_path = tmpdir\n assignment_map = {\"Intervention\": 1, \"Control\": 0}\n assignment_description_map = {\"Intervention\": \"Fluconazole plus flucytosine\", \"Control\": \"Fluconazole\"}\n extra_csv_fieldnames = [\"gender\"]\n\n def __init__(self, gender=None, **kwargs):\n self.gender = gender\n super().__init__(**kwargs)\n\n @property\n def extra_required_instance_attrs(self):\n return dict(gender=self.gender)\n\n @property\n def extra_model_obj_options(self):\n return dict(gender=self.gender)\n\n @classmethod\n def get_extra_list_display(cls):\n return [(4, \"gender\")]\n\n\nThe ``register()`` decorator registers the custom class with ``site_randomizers``.\n\nWith a custom randomizer, the default ``Randomizer`` class is no longer needed,\nupdate settings to prevent the default class from registering.\n\nUse the settings attribute:\n\n.. code-block:: python\n\n EDC_RANDOMIZATION_REGISTER_DEFAULT_RANDOMIZER = False\n\nConfirm this by checking the ``site_randomizers``:\n\n.. code-block:: python\n\n >>> randomizer_cls = site_randomizers.get(\"default\")\n NotRegistered: A Randomizer class by this name ...\n\n >>> randomizer_cls = site_randomizers.get(\"my_randomizer\")\n >>> randomizer_cls.name\n \"my_randomizer\"\n\n\nManually Importing from CSV\n+++++++++++++++++++++++++++\nA ``Randomizer`` class will call ``import_list`` when it is instantiated\nfor the first time. If you want to load the CSV file manually,\nimport the ``Randomizer`` class and call ``import_list()``.\n\n\n.. code-block:: python\n\n >>> randomizer_cls = site_randomizers.get(\"my_randomizer\")\n >>> randomizer_cls.import_list()\n Import CSV data\n Randomizer:\n - Name: my_randomizer\n - Assignments: {'active': 1, 'placebo': 2}\n - Model: edc_randomization.myrandomizationlist\n - Path: /home/me/.etc/randomization_list.csv\n - Imported 5 SIDs for randomizer `my_randomizer` into model `edc_randomization.myrandomizationlist`\n from /home/me/.etc/randomization_list.csv.\n - Verified OK.\n\n\nManually Export to CSV\n++++++++++++++++++++++\n\n.. code-block:: python\n\n >>> from edc_randomization.utils import export_randomization_list\n >>> export_randomization_list(randomizer_name=\"default\",path=\"~/\", username=\"erikvw\")\n\nIf the user does not have permissions to view the randomizationlist table, a ``RandomizationListExporterError`` will be raised:\n\n.. code-block:: python\n\n RandomizationListExporterError: User `erikvw` does not have permission to view 'edc_randomization.randomizationlist'\n\n\n.. |pypi| image:: https://img.shields.io/pypi/v/edc-randomization.svg\n :target: https://pypi.python.org/pypi/edc-randomization\n\n.. |actions| image:: https://github.com/clinicedc/edc-randomization/actions/workflows/build.yml/badge.svg\n :target: https://github.com/clinicedc/edc-randomization/actions/workflows/build.yml\n\n.. |codecov| image:: https://codecov.io/gh/clinicedc/edc-randomization/branch/develop/graph/badge.svg\n :target: https://codecov.io/gh/clinicedc/edc-randomization\n\n.. |downloads| image:: https://pepy.tech/badge/edc-randomization\n :target: https://pepy.tech/project/edc-randomization\n",
"bugtrack_url": null,
"license": "GPL license, see LICENSE",
"summary": "Randomization classes for clinicedc/edc",
"version": "0.3.56",
"project_urls": {
"Homepage": "https://github.com/clinicedc/edc-randomization"
},
"split_keywords": [
"django edc randomization",
" clinicedc",
" clinical trials"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "184b6ab1e6352721ac08b2e464b3e61b2d37198b171dc4776788ab087943cd94",
"md5": "2ce0267d79548b17dea034d61b4ab104",
"sha256": "25fba3f3e4115da2f4284a3f4713c648c2eeec3d75b0cb292e1d9e8691a91363"
},
"downloads": -1,
"filename": "edc_randomization-0.3.56-py3-none-any.whl",
"has_sig": false,
"md5_digest": "2ce0267d79548b17dea034d61b4ab104",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 65160,
"upload_time": "2024-03-20T20:42:30",
"upload_time_iso_8601": "2024-03-20T20:42:30.360816Z",
"url": "https://files.pythonhosted.org/packages/18/4b/6ab1e6352721ac08b2e464b3e61b2d37198b171dc4776788ab087943cd94/edc_randomization-0.3.56-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "2b27b848077c9a0f263433fc34aac1bde3fdb964a2e441c7fe0044dcbbd8be20",
"md5": "23bc4238870d9d5df0be1e5dd1a25762",
"sha256": "5a9937180d2df85c0b105e1665a9dfb1cd6a2257b2d6c637fc8c840a785b7f96"
},
"downloads": -1,
"filename": "edc-randomization-0.3.56.tar.gz",
"has_sig": false,
"md5_digest": "23bc4238870d9d5df0be1e5dd1a25762",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 54768,
"upload_time": "2024-03-20T20:42:32",
"upload_time_iso_8601": "2024-03-20T20:42:32.651640Z",
"url": "https://files.pythonhosted.org/packages/2b/27/b848077c9a0f263433fc34aac1bde3fdb964a2e441c7fe0044dcbbd8be20/edc-randomization-0.3.56.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-03-20 20:42:32",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "clinicedc",
"github_project": "edc-randomization",
"travis_ci": false,
"coveralls": true,
"github_actions": true,
"lcname": "edc-randomization"
}