{ "cells": [ { "cell_type": "markdown", "id": "423d701a", "metadata": { "toc": true }, "source": [ "

Table of Contents

\n", "
" ] }, { "cell_type": "code", "execution_count": 1, "id": "b465c974", "metadata": {}, "outputs": [], "source": [ "# Setup\n", "import math as m" ] }, { "cell_type": "markdown", "id": "34eb9ec9", "metadata": {}, "source": [ "# SAFER Wearables Planning\n" ] }, { "cell_type": "code", "execution_count": null, "id": "81ca143e", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "444cb2a8", "metadata": {}, "source": [ "## Recruitment\n", "\n", "The following sections are used to calculate the number of GP Practices required, and the number of potential participants to be approached at each GP Practice." ] }, { "cell_type": "markdown", "id": "9a0edd9a", "metadata": {}, "source": [ "### Assumptions\n", "\n", "- SAFER Wearables Study" ] }, { "cell_type": "code", "execution_count": 2, "id": "2917e06c", "metadata": {}, "outputs": [], "source": [ "n_pts = 130 # Total number of participants in SAFER Wearables\n", "n_AF_pts = n_pts/2 # Number of AF participants\n", "n_nonAF_pts = n_pts/2 # Number of non-AF participants" ] }, { "cell_type": "markdown", "id": "1785562a", "metadata": {}, "source": [ "- SAFER Programme" ] }, { "cell_type": "code", "execution_count": 3, "id": "c63f062b", "metadata": {}, "outputs": [], "source": [ "n_safer_pts_per_prac = 350 # Number of SAFER Programme participants per practice\n", "AF_rate = 0.03 # Proportion of participants diagnosed with AF in SAFER Programme" ] }, { "cell_type": "markdown", "id": "d57f8547", "metadata": {}, "source": [ "- Recruitment" ] }, { "cell_type": "code", "execution_count": 4, "id": "30fe48d9", "metadata": {}, "outputs": [], "source": [ "n_suggested_per_practice = 45 # number of potential participants suggested to each practice\n", "prop_contacted = 0.8 # proportion of SAFER participants who are suitable for the SAFER Wearables study who will be contacted by their practice (remaidner won't be due to changing practice, or not meeting the eligibility criteria)" ] }, { "cell_type": "markdown", "id": "1dd38432", "metadata": {}, "source": [ "- Participation" ] }, { "cell_type": "code", "execution_count": 5, "id": "79af6119", "metadata": {}, "outputs": [], "source": [ "participation_rate = 0.5 # proportion of invitees who will participate" ] }, { "cell_type": "markdown", "id": "87d82312", "metadata": {}, "source": [ "### Participant numbers for an individual GP Practice" ] }, { "cell_type": "code", "execution_count": 6, "id": "ea0b193a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Number suggested potential participants per practice: 45 (10 AF, 35 non-AF)\n", "Number invitations per practice: 36 (8 AF, 28 non-AF)\n", "Expected number SAFER Wearables participants per practice: 18 (4 AF, 14 non-AF)\n" ] } ], "source": [ "# - SAFER participants\n", "n_safer_AF_pts_per_prac = m.floor(AF_rate*n_safer_pts_per_prac)\n", "n_safer_nonAF_pts_per_prac = m.floor((1-AF_rate)*n_safer_pts_per_prac)\n", "\n", "# - Suggested possible participants\n", "n_safer_AF_pts_per_prac_suggested = n_safer_AF_pts_per_prac\n", "n_safer_nonAF_pts_per_prac_suggested = n_suggested_per_practice - n_safer_AF_pts_per_prac_suggested\n", "n_safer_pts_per_prac_suggested = n_safer_AF_pts_per_prac_suggested + n_safer_nonAF_pts_per_prac_suggested\n", "print(\"Number suggested potential participants per practice: %d (%d AF, %d non-AF)\" % (n_safer_pts_per_prac_suggested, n_safer_AF_pts_per_prac_suggested, n_safer_nonAF_pts_per_prac_suggested))\n", "\n", "# - invitations\n", "n_AF_pts_invited_per_prac = m.floor(n_safer_AF_pts_per_prac_suggested*prop_contacted)\n", "n_nonAF_pts_invited_per_prac = m.floor(n_safer_nonAF_pts_per_prac_suggested*prop_contacted)\n", "n_invites_per_prac = n_nonAF_pts_invited_per_prac + n_AF_pts_invited_per_prac\n", "print(\"Number invitations per practice: %d (%d AF, %d non-AF)\" % (n_invites_per_prac, n_AF_pts_invited_per_prac, n_nonAF_pts_invited_per_prac))\n", "\n", "# - participants\n", "n_AF_pts_per_prac = m.floor(n_AF_pts_invited_per_prac*participation_rate)\n", "n_nonAF_pts_per_prac = m.floor(n_nonAF_pts_invited_per_prac*participation_rate)\n", "n_pts_per_prac = n_AF_pts_per_prac + n_nonAF_pts_per_prac\n", "print(\"Expected number SAFER Wearables participants per practice: %d (%d AF, %d non-AF)\" % (n_pts_per_prac, n_AF_pts_per_prac, n_nonAF_pts_per_prac))" ] }, { "cell_type": "markdown", "id": "9d93f56f", "metadata": {}, "source": [ "### Number of GP Practices required" ] }, { "cell_type": "markdown", "id": "e7f54572", "metadata": {}, "source": [ "- Calculated based on the expected number of SAFER participants per practice:" ] }, { "cell_type": "code", "execution_count": 7, "id": "c97161f6", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "No. GP Practices required: 17 (17 for AF, and 5 for non-AF)\n" ] } ], "source": [ "no_practices_for_AF = m.ceil(n_AF_pts/n_AF_pts_per_prac) # no. practices required to reach the required number of AF participants\n", "no_practices_for_nonAF = m.ceil(n_nonAF_pts/n_nonAF_pts_per_prac) # no. practices required to reach the required number of non-AF participants\n", "no_practices = max([no_practices_for_AF, no_practices_for_nonAF])\n", "print(\"No. GP Practices required: %d (%d for AF, and %d for non-AF)\" % (no_practices, no_practices_for_AF, no_practices_for_nonAF))" ] }, { "cell_type": "markdown", "id": "22470c31", "metadata": {}, "source": [ "_Based on this approach, 17 practices are required, and each practice needs to have 10 potential AF participants._" ] }, { "cell_type": "markdown", "id": "4c3fb5a2", "metadata": {}, "source": [ "- Calculated based on the number of Practices who will participate:" ] }, { "cell_type": "code", "execution_count": 8, "id": "21169785", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Ave no. of potential AF participants required per practice (if 19 practices participate): 8.6\n" ] } ], "source": [ "no_practices_to_participate = 19 # no. practices which will participate\n", "ave_no_potential_af_participants_per_practice = n_AF_pts/(no_practices_to_participate*prop_contacted*participation_rate)\n", "print(\"Ave no. of potential AF participants required per practice (if %d practices participate): %.1f\" % (no_practices_to_participate, ave_no_potential_af_participants_per_practice))" ] }, { "cell_type": "markdown", "id": "b6f74c0c", "metadata": {}, "source": [ "_Based on this approach, each practice should have (on average) 8.6 potential AF participants. Therefore, you could for instance approach practices with at least 6 potential AF participants, assuming that on average this will provide an average of at least 8.6 potential AF participants per practice._\n", "\n", "_If all the non-AF participants are enrolled early in the study (likely as they are expected to be enrolled in the first 5 Practices), then it might be worth exploring only recruiting AF participants from that point onwards, which may allow a greater number of practices to participate._" ] }, { "cell_type": "markdown", "id": "d6e1e1c0", "metadata": {}, "source": [ "## Costs" ] }, { "cell_type": "markdown", "id": "cd1206f9", "metadata": {}, "source": [ "### Assumptions" ] }, { "cell_type": "markdown", "id": "710c1dfc", "metadata": {}, "source": [ "- Costs of devices" ] }, { "cell_type": "code", "execution_count": 9, "id": "e3982822", "metadata": {}, "outputs": [], "source": [ "# actual costs of devices\n", "act_cost_wrist_ppg_device = 148 # actual cost of wrist-worn PPG device (GBP)\n", "act_cost_wrist_ecg_device = 130 # actual cost of wrist-worn ECG device (GBP)\n", "act_cost_mobile_phone = 100 # actual cost of mobile phone (GBP)\n", "# NB: cost of reference ECG chest-patch device not included, as this has been purchased already\n", "\n", "# permitted costs of devices\n", "perm_cost_wrist_ppg_device = 151 # actual cost of wrist-worn PPG device (GBP)\n", "perm_cost_wrist_ecg_device = 100 # actual cost of wrist-worn ECG device (GBP)\n", "perm_cost_mobile_phone = 100 # actual cost of mobile phone (GBP)\n" ] }, { "cell_type": "markdown", "id": "c55cf744", "metadata": {}, "source": [ "- Number of device kits" ] }, { "cell_type": "code", "execution_count": 8, "id": "ef85bd65", "metadata": {}, "outputs": [], "source": [ "# No. device kits\n", "no_kits_with_phone = 20\n", "no_kits_without_phone = 0\n", "no_of_each_wearable = no_kits_with_phone + no_kits_without_phone # no. of each wearable to be purchased\n", "no_mobile_phones = no_kits_with_phone" ] }, { "cell_type": "markdown", "id": "b5e6e409", "metadata": {}, "source": [ "### Costs of devices\n", "This calculates any overspend in purchasing the devices relative to the funding available." ] }, { "cell_type": "code", "execution_count": null, "id": "59698dcd", "metadata": {}, "outputs": [], "source": [ "# calculate over spend\n", "wrist_ppg_device_overspend = max(0, no_of_each_wearable*(act_cost_wrist_ppg_device-perm_cost_wrist_ppg_device))\n", "wrist_ecg_device_overspend = max(0, no_of_each_wearable*(act_cost_wrist_ecg_device-perm_cost_wrist_ecg_device))\n", "mobile_phone_overspend = max(0, no_mobile_phones*(act_cost_mobile_phone-perm_cost_mobile_phone))\n", "total_overspend = wrist_ppg_device_overspend + wrist_ecg_device_overspend + mobile_phone_overspend\n", "print(\"Total overspend: \\xA3%.2f\" % (total_overspend)) # NB: \\xA3 is the pound-sign\n", "print(\" - PPG devices: \\xA3%.2f\" % (wrist_ppg_device_overspend))\n", "print(\" - ECG devices: \\xA3%.2f\" % (wrist_ecg_device_overspend))\n", "print(\" - mobile phones: \\xA3%.2f\" % (mobile_phone_overspend))" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.8" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": true, "toc_position": {}, "toc_section_display": true, "toc_window_display": false } }, "nbformat": 4, "nbformat_minor": 5 }