{ "cells": [ { "attachments": { "oxcin.png": { "image/png": "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dHMvMS4xLyIKICAgIHhtbG5zOkdJTVA9Imh0dHA6Ly93d3cuZ2ltcC5vcmcveG1wLyIKICAgIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIgogICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICB4bXBNTTpEb2N1bWVudElEPSJnaW1wOmRvY2lkOmdpbXA6MDVmOTRjOTQtNjJiMC00MTNlLWExZjQtODdhZTBjMzBmNDE0IgogICB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOmM1MDVlYTNhLTJiYTUtNDg3YS1iNThhLWI5OWY2MDc5MDZlOSIKICAgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOmM1ODgzZGRmLTM2N2QtNDQ1NC1hN2Y0LTRkZGUzMTIxNWMwMyIKICAgZGM6Rm9ybWF0PSJpbWFnZS9wbmciCiAgIEdJTVA6QVBJPSIyLjAiCiAgIEdJTVA6UGxhdGZvcm09IkxpbnV4IgogICBHSU1QOlRpbWVTdGFtcD0iMTc4MTUxOTEwMzY2OTU5MSIKICAgR0lNUDpWZXJzaW9uPSIyLjEwLjMwIgogICB0aWZmOk9yaWVudGF0aW9uPSIxIgogICB4bXA6Q3JlYXRvclRvb2w9IkdJTVAgMi4xMCI+CiAgIDx4bXBNTTpIaXN0b3J5PgogICAgPHJkZjpTZXE+CiAgICAgPHJkZjpsaQogICAgICBzdEV2dDphY3Rpb249InNhdmVkIgogICAgICBzdEV2dDpjaGFuZ2VkPSIvIgogICAgICBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjI0NmIwYjI2LTM2ZGUtNGJiMS04ODg4LTEyODRiMjJlN2QzYyIKICAgICAgc3RFdnQ6c29mdHdhcmVBZ2VudD0iR2ltcCAyLjEwIChMaW51eCkiCiAgICAgIHN0RXZ0OndoZW49IjIwMjYtMDYtMTVUMTE6MjU6MDMrMDE6MDAiLz4KICAgIDwvcmRmOlNlcT4KICAgPC94bXBNTTpIaXN0b3J5PgogIDwvcmRmOkRlc2NyaXB0aW9uPgogPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIAo8P3hwYWNrZXQgZW5kPSJ3Ij8+7RK8kAAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB+oGDwoZA6O2CsYAACAASURBVHja7J11YFXl/8df58buupMVCzZGjO6WVlKQRhoJASkRJMVAaREMDEJBQFBElJLuHLlkYxvrzru7G+f3x+ZYwuDrz+8XPK//du+5557d85zn/XzyEeITU8SQsEgQBCQknjdq1/LCxcl+myAIo571HKIoGgOxgL30i0o8r8Tl5ROWkfX0HyzQQELy02mAKFLbzxtFSHgkLw1eAAqZdAcknjtO/fgBLk7SvC8hcS81nW6XgoCnNAYSkuGTHSB/is/pDBzf/SEKEIrEQxIQiecQAclylpDgL9l4Fk+SUKwBcuGpv1FSDQkJCQmJZ0ISEAkJCQkJSUAkJCQkJCQBkZCQkJCQBERCQkJCQhIQCQkJCQkJSUAkJCQkJCQBkZCQkJCQBERCQkJC4vlAIf0ELzCiCAZAIcNcpcTZ0hhZcaVqoU5PYq6GArW26DiZgFTULSEhIQnIvxWdAbm5CWO7NiQwwAcnZyc83V2ws7VCJpNjZGRU0urAYDCg02ox6LTEJqQQG5dISlISp6/cY//pEBAMRaIiIfE8PxKiSHqBBhFwMFaVLKAkJAGRACyM5DSuVYMh/V6icaN61PL2QCaXk5iURlpqKrEP4zl+5grJKenk5eU/+qAA1laW1HB2wM/LFT8fT9q1bsaEscNQqwu4GxLBqXNX2f/HOe7EZaAziNKPLfF8GN5AWHomv0RGcyMlg0itFr0o0tTcjCn1a9PA0a7M8dFZOZyIjcfXyoKGzg6YKZWSMS4JyAuMQaSeuy2vD+xM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" } }, "cell_type": "markdown", "id": "170a17e3-fdd0-4de2-a3e9-26ba02b5a48d", "metadata": {}, "source": [ "# FUNPACK overview\n", "\n", "\n", "\n", "> **Note:** If you have FUNPACK installed, you can start an interactive\n", "> version of this page by running `fmrib_unpack_demo`.\n", "\n", "FUNPACK is a command-line program which you can use to extract data from UK\n", "Biobank (and other tabular) data. You can run FUNPACK by calling the\n", "`fmrib_unpack` command.\n", "\n", "You can give FUNPACK one or more input files (e.g.\u00a0`.csv`, `.tsv`), and it\n", "will merge them together, perform some preprocessing, and produce a single\n", "output file.\n", "\n", "A large number of rules are built into FUNPACK which are specific to UK\n", "Biobank data. But you can control and customise everything that FUNPACK\n", "does to your data, including which rows and columns to extract, and which\n", "cleaning/processing steps to perform on each column.\n", "\n", "**Important** The examples in this notebook assume that you have installed\n", "FUNPACK 4.0.1 or newer.\n", "\n", "> **Note:** The `fmrib_unpack` command was called `funpack` in older versions\n", "> of FUNPACK, but was changed to `fmrib_unpack` in 3.0.0 to avoid a naming\n", "> conflict with an [unrelated software\n", "> package](https://heasarc.gsfc.nasa.gov/fitsio/)." ] }, { "cell_type": "code", "execution_count": 1, "id": "06da40eb-248a-4af9-be66-3fb10df8fa45", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:03.526235Z", "iopub.status.busy": "2026-06-15T10:54:03.526113Z", "iopub.status.idle": "2026-06-15T10:54:03.861908Z", "shell.execute_reply": "2026-06-15T10:54:03.861530Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "funpack 4.0.1.dev10+g2ea26548b\n" ] } ], "source": [ "fmrib_unpack -V" ] }, { "cell_type": "markdown", "id": "076b0d51-7db9-4eda-a8f8-edf394a5e6f9", "metadata": {}, "source": [ "> **Note:** If the above command produces a `NameError`, you may need to\n", "> change the Jupyter Notebook kernel type to **Bash** - you can do so via the\n", "> **Kernel -\\> Change Kernel** menu option.\n", "\n", "## Contents\n", "\n", "1. [Overview](#Overview)\n", "2. [Examples](#Examples)\n", "3. [Import examples](#Import-examples)\n", "4. [Cleaning examples](#Cleaning-examples)\n", "5. [Processing examples](#Processing-examples)\n", "6. [Custom cleaning, processing and loading - FUNPACK plugins](#Custom-cleaning,-processing-and-loading---FUNPACK-plugins)\n", "7. [Miscellaneous topics](#Miscellaneous-topics)\n", "\n", "## Overview\n", "\n", "FUNPACK performs the following steps:\n", "\n", "1. [Import](#1.-Import)\n", "2. [Cleaning](#2.-Cleaning)\n", "3. [Processing](#3.-Processing)\n", "4. [Export](#4.-Export)\n", "\n", "### 1. Import\n", "\n", "All data files are loaded in, unwanted data-fields and subjects are dropped, and\n", "the data files are merged into a single table (a.k.a. data frame). Multiple\n", "files can be merged according to an index column (e.g.\u00a0subject ID). Or, if the\n", "input files contain the same columns/subjects, they can be naively\n", "concatenated along rows or columns.\n", "\n", "> *Note:* FUNPACK refers to UK Biobank **Data-fields** as **variables**. The\n", "> two terms can be considered interchangeable. Also note that multiple columns\n", "> may map to one data-field (e.g.\u00a0for data-fields collected at each assessment\n", "> centre visit).\n", "\n", "### 2. Cleaning\n", "\n", "The following cleaning steps are applied to each column:\n", "\n", "1. **NA value replacement:** Specific values for some data-fields are replaced\n", " with NA, for example, data-fields where a value of `-1` indicates *Do not\n", " know*.\n", "\n", "2. **Data-field-specific cleaning functions:** Certain data-fields are\n", " re-formatted; for example, the [ICD10](https://en.wikipedia.org/wiki/ICD-10)\n", " disease codes can be converted to integer representations.\n", "\n", "3. **Categorical recoding:** Certain categorical data-fields are re-coded.\n", "\n", "4. **Child value replacement:** NA values within some data-fields which are\n", " dependent upon other data-fields may have values inserted based on the\n", " values of their parent data-fields.\n", "\n", "### 3. Processing\n", "\n", "During the processing stage, columns may be removed, merged, or expanded into\n", "additional columns. For example, a categorical column may be expanded into a set\n", "of binary columns, one for each category.\n", "\n", "A column may also be removed on the basis of being too sparse, or being\n", "redundant with respect to another column.\n", "\n", "### 4. Export\n", "\n", "The processed data can be saved as a `.csv`, `.tsv`, or `.hdf5` file.\n", "\n", "## Examples\n", "\n", "Throughout these examples, we are going to use a few command line options,\n", "which you will probably **not** normally want to use:\n", "\n", "- `-ow` (short for `--overwrite`): This tells `fmrib_unpack` not to complain\n", " if the output file already exists.\n", "\n", "- `-nd` (short for `--no_download`): This tells `fmrib_unpack` to use built-in\n", " copies of the UK Biobank schema files, instead of downloading the latest\n", " versions.\n", "\n", "- `-q` (short for `--quiet`): This tells `fmrib_unpack` to be quiet. Without\n", " the `-q` option, `fmrib_unpack` can be quite verbose, which can be\n", " annoying, but is very useful when things go wrong. When using `fmrib_unpack`\n", " for real, a good strategy is to tell it to produce verbose output using the\n", " `--noisy` (`-n` for short) option, and to send all of its output to a log\n", " file with the `--log_file` (or `-lf`) option. For example:\n", "\n", " > fmrib_unpack -n -n -n -lf log.txt out.tsv in.tsv" ] }, { "cell_type": "code", "execution_count": 2, "id": "959f40c9-3122-4714-97ef-9349aee769ba", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:03.862766Z", "iopub.status.busy": "2026-06-15T10:54:03.862680Z", "iopub.status.idle": "2026-06-15T10:54:03.971261Z", "shell.execute_reply": "2026-06-15T10:54:03.970715Z" } }, "outputs": [], "source": [ "alias fmrib_unpack=\"fmrib_unpack -ow -nd -q\"" ] }, { "cell_type": "markdown", "id": "e424e5c0-8179-456d-9a28-b15d6dcb1d31", "metadata": {}, "source": [ "Here\u2019s the first example input data set, with UK Biobank-style column names:" ] }, { "cell_type": "code", "execution_count": 3, "id": "404e012f-c513-4060-82db-066dd961ae05", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:03.972302Z", "iopub.status.busy": "2026-06-15T10:54:03.972204Z", "iopub.status.idle": "2026-06-15T10:54:04.082941Z", "shell.execute_reply": "2026-06-15T10:54:04.082346Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\t4-0.0\t5-0.0\t6-0.0\t7-0.0\t8-0.0\t9-0.0\t10-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t31\t65\t10\t11\t84\t22\t56\t65\t90\t12\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t56\t52\t52\t42\t89\t35\t3\t65\t50\t67\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t45\t84\t20\t84\t93\t36\t96\t62\t48\t59\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t7\t46\t37\t48\t80\t20\t18\t72\t37\t27\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t8\t86\t51\t68\t80\t84\t11\t28\t69\t10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t6\t29\t85\t59\t7\t46\t14\t60\t73\t80\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t24\t49\t41\t46\t92\t23\t39\t68\t7\t63\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t80\t92\t97\t30\t92\t83\t98\t36\t6\t23\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t84\t59\t89\t79\t16\t12\t95\t73\t2\t62\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t23\t96\t67\t41\t8\t20\t97\t57\t59\t23\n" ] } ], "source": [ "cat data_01.tsv" ] }, { "cell_type": "markdown", "id": "21c9b932-4a42-47a8-849c-a6a57449afcb", "metadata": {}, "source": [ "The numbers in each column name typically represent:\n", "\n", "1. The data-field ID\n", "2. The \u201cinstance\u201d, usually corresponding to the assessment centre visit,\n", " for data-fields which were collected at multiple points in time.\n", "3. The index, for multi-valued data-fields.\n", "\n", "> FUNPACK understands UK Biobank column names which conform to any of these\n", "> formats:\n", ">\n", "> - `-.` (e.g.\u00a0`31-0.0`)\n", "> - `f...` (e.g.\u00a0`f.31.0.0`)\n", "> - `p[_i][_a]` (e.g.\u00a0`p31`)\n", "\n", "Note that one **data-field** is typically associated with several **columns**,\n", "although we\u2019re keeping things simple for this first example - there is only\n", "one visit for each data-field, and there are no multi-valued data-fields.\n", "\n", "> *Most but not all* data-fields in the UK Biobank contain data collected\n", "> at different visits, the times that the participants visited a UK Biobank\n", "> assessment centre. The instance number in the column name identifies the\n", "> assessment centre visit. However there are some data-fields (e.g.\u00a0[ICD10\n", "> diagnosis\n", "> codes](https://biobank.ctsu.ox.ac.uk/crystal/field.cgi?id=41202)) for\n", "> which this is not the case.\n", "\n", "## Import examples\n", "\n", "### Selecting data-fields (columns)\n", "\n", "You can specify which data-fields you want to load in the following ways, using\n", "the `--variable` (`-v` for short), `--category` (`-c` for short) and\n", "`--column` (`-co` for short) command line options:\n", "\n", "- By data-field ID.\n", "- By data-field ranges.\n", "- By a text file which contains the IDs you want to keep.\n", "- By pre-defined data-field categories.\n", "- By column name.\n", "\n", "#### Selecting individual data-fields\n", "\n", "Simply provide the IDs of the data-fields you want to extract:" ] }, { "cell_type": "code", "execution_count": 4, "id": "0649bc52-b3c5-4a85-9c97-2d4f318b859b", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:04.084489Z", "iopub.status.busy": "2026-06-15T10:54:04.084365Z", "iopub.status.idle": "2026-06-15T10:54:04.538767Z", "shell.execute_reply": "2026-06-15T10:54:04.538309Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t5-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t31\t84.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t56\t89.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t45\t93.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t7\t80.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t8\t80.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t6\t7.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t24\t92.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t80\t92.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t84\t16.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t23\t8.0\n" ] } ], "source": [ "fmrib_unpack -v 1,5 out.tsv data_01.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "89dd7a26-e14b-4373-90b1-6c5144afa756", "metadata": {}, "source": [ "#### Selecting data-field ranges\n", "\n", "The `--variable`/`-v` option accepts MATLAB-style ranges of the form\n", "`start:step:stop` (where the `stop` is inclusive):" ] }, { "cell_type": "code", "execution_count": 5, "id": "43371b06-3c31-4358-9b12-f55865f1f277", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:04.539777Z", "iopub.status.busy": "2026-06-15T10:54:04.539696Z", "iopub.status.idle": "2026-06-15T10:54:04.991813Z", "shell.execute_reply": "2026-06-15T10:54:04.991290Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t4-0.0\t7-0.0\t10-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t31\t11.0\t56\t12\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t56\t42.0\t3\t67\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t45\t84.0\t96\t59\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t7\t48.0\t18\t27\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t8\t68.0\t11\t10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t6\t59.0\t14\t80\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t24\t46.0\t39\t63\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t80\t30.0\t98\t23\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t84\t79.0\t95\t62\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t23\t41.0\t97\t23\n" ] } ], "source": [ "fmrib_unpack -v 1:3:10 out.tsv data_01.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "70327473-40c7-428d-9c9a-d63551b29b16", "metadata": {}, "source": [ "#### Selecting data-fields with a file\n", "\n", "If your data-fields of interest are listed in a plain-text file, you can simply\n", "pass that file:" ] }, { "cell_type": "code", "execution_count": 6, "id": "dc8276d1-3055-481b-9d58-382d102d8cfb", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:04.992780Z", "iopub.status.busy": "2026-06-15T10:54:04.992699Z", "iopub.status.idle": "2026-06-15T10:54:05.495610Z", "shell.execute_reply": "2026-06-15T10:54:05.495168Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t6-0.0\t9-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t31\t22.0\t90\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t56\t35.0\t50\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t45\t36.0\t48\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t7\t20.0\t37\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t8\t84.0\t69\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t6\t46.0\t73\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t24\t23.0\t7\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t80\t83.0\t6\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t84\t12.0\t2\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t23\t20.0\t59\n" ] } ], "source": [ "echo -e \"1\\n6\\n9\" > vars.txt\n", "fmrib_unpack -v vars.txt out.tsv data_01.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "22e2f78a-721c-4bc7-b29a-ae0b14941bc1", "metadata": {}, "source": [ "#### Selecting data-fields from pre-defined categories\n", "\n", "Some UK Biobank-specific categories are\n", "[built into FUNPACK](#Built-in-rules), but you can also define your own\n", "categories - you just need to create a `.tsv` file, and pass it to\n", "FUNPACK via the `--category_file` (`-cf` for short):" ] }, { "cell_type": "code", "execution_count": 7, "id": "71d61568-31e4-4715-ae8f-00d00c9c88b1", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:05.496582Z", "iopub.status.busy": "2026-06-15T10:54:05.496495Z", "iopub.status.idle": "2026-06-15T10:54:05.768125Z", "shell.execute_reply": "2026-06-15T10:54:05.767351Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ID\tCategory\tVariables\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\tGood data-fields\t1:5,7\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\tBad data-fields\t6,8:10\n" ] } ], "source": [ "echo -e \"ID\\tCategory\\tVariables\" > custom_categories.tsv\n", "echo -e \"1\\tGood data-fields\\t1:5,7\" >> custom_categories.tsv\n", "echo -e \"2\\tBad data-fields\\t6,8:10\" >> custom_categories.tsv\n", "cat custom_categories.tsv" ] }, { "cell_type": "markdown", "id": "b529573c-b2a6-4b81-a4b2-bf41a737ac25", "metadata": {}, "source": [ "Use the `--category` (`-c` for short) to select categories to output. You can\n", "refer to categories by their ID:" ] }, { "cell_type": "code", "execution_count": 8, "id": "8d4ffd39-da34-4360-b03f-eb3f0f39ba9f", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:05.769941Z", "iopub.status.busy": "2026-06-15T10:54:05.769817Z", "iopub.status.idle": "2026-06-15T10:54:06.230293Z", "shell.execute_reply": "2026-06-15T10:54:06.229858Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\t4-0.0\t5-0.0\t7-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t31\t65\t10.0\t11.0\t84.0\t56\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t56\t52\t52.0\t42.0\t89.0\t3\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t45\t84\t20.0\t84.0\t93.0\t96\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t7\t46\t37.0\t48.0\t80.0\t18\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t8\t86\t51.0\t68.0\t80.0\t11\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t6\t29\t85.0\t59.0\t7.0\t14\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t24\t49\t41.0\t46.0\t92.0\t39\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t80\t92\t97.0\t30.0\t92.0\t98\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t84\t59\t89.0\t79.0\t16.0\t95\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t23\t96\t67.0\t41.0\t8.0\t97\n" ] } ], "source": [ "fmrib_unpack -cf custom_categories.tsv -c 1 out.tsv data_01.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "f45aca91-9edc-4776-baa5-7f27e5cc2024", "metadata": {}, "source": [ "Or by name:" ] }, { "cell_type": "code", "execution_count": 9, "id": "dded9c2b-7dc1-4e68-ade4-4cf6a1ca2dcd", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:06.231244Z", "iopub.status.busy": "2026-06-15T10:54:06.231169Z", "iopub.status.idle": "2026-06-15T10:54:06.672298Z", "shell.execute_reply": "2026-06-15T10:54:06.671760Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t6-0.0\t8-0.0\t9-0.0\t10-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t22.0\t65\t90\t12\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t35.0\t65\t50\t67\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t36.0\t62\t48\t59\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t20.0\t72\t37\t27\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t84.0\t28\t69\t10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t46.0\t60\t73\t80\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t23.0\t68\t7\t63\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t83.0\t36\t6\t23\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t12.0\t73\t2\t62\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t20.0\t57\t59\t23\n" ] } ], "source": [ "fmrib_unpack -cf custom_categories.tsv -c bad out.tsv data_01.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "d56146dc-6187-48ef-b3da-1fcb373440f8", "metadata": {}, "source": [ "#### Selecting column names\n", "\n", "If you are working with data that has non-UK Biobank style column names, you\n", "can use the `--column` (`-co` for short) to select individual columns by their\n", "name, rather than the data-field with which they are associated. The `--column`\n", "option accepts full column names, and also shell-style wildcard patterns:" ] }, { "cell_type": "code", "execution_count": 10, "id": "3f065279-afff-42dc-9059-d365034f26a7", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:06.673230Z", "iopub.status.busy": "2026-06-15T10:54:06.673153Z", "iopub.status.idle": "2026-06-15T10:54:07.128018Z", "shell.execute_reply": "2026-06-15T10:54:07.127387Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t4-0.0\t10-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t11.0\t12\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t42.0\t67\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t84.0\t59\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t48.0\t27\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t68.0\t10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t59.0\t80\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t46.0\t63\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t30.0\t23\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t79.0\t62\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t41.0\t23\n" ] } ], "source": [ "fmrib_unpack -co 4-0.0 -co \"??-0.0\" out.tsv data_01.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "a6afa2a0-b5da-4c86-b9ce-190938d2aff6", "metadata": {}, "source": [ "### Selecting subjects (rows)\n", "\n", "FUNPACK assumes that the first column in every input file is a subject ID,\n", "usually labelled `eid`. You can specify which subjects you want to load via the\n", "`--subject` (`-s` for short) option. You can specify subjects in the same way\n", "that you specified data-fields above, and also:\n", "\n", "- By specifying a conditional expression on data-field values - only subjects\n", " for which the expression evaluates to true will be imported\n", "- By specifying subjects to exclude\n", "\n", "#### Selecting individual subjects" ] }, { "cell_type": "code", "execution_count": 11, "id": "4a792948-06ff-4677-84aa-4b69fb366ab1", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:07.129062Z", "iopub.status.busy": "2026-06-15T10:54:07.128972Z", "iopub.status.idle": "2026-06-15T10:54:07.572380Z", "shell.execute_reply": "2026-06-15T10:54:07.571935Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\t4-0.0\t5-0.0\t6-0.0\t7-0.0\t8-0.0\t9-0.0\t10-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t31\t65\t10.0\t11.0\t84.0\t22.0\t56\t65\t90\t12\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t45\t84\t20.0\t84.0\t93.0\t36.0\t96\t62\t48\t59\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t8\t86\t51.0\t68.0\t80.0\t84.0\t11\t28\t69\t10\n" ] } ], "source": [ "fmrib_unpack -s 1,3,5 out.tsv data_01.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "36963765-445c-4edc-9552-0f2c61b0920e", "metadata": {}, "source": [ "#### Selecting subject ranges" ] }, { "cell_type": "code", "execution_count": 12, "id": "e49037e1-9585-42e1-9ec0-e2871b1c1d8f", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:07.573329Z", "iopub.status.busy": "2026-06-15T10:54:07.573235Z", "iopub.status.idle": "2026-06-15T10:54:08.011909Z", "shell.execute_reply": "2026-06-15T10:54:08.011489Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\t4-0.0\t5-0.0\t6-0.0\t7-0.0\t8-0.0\t9-0.0\t10-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t56\t52\t52.0\t42.0\t89.0\t35.0\t3\t65\t50\t67\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t7\t46\t37.0\t48.0\t80.0\t20.0\t18\t72\t37\t27\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t6\t29\t85.0\t59.0\t7.0\t46.0\t14\t60\t73\t80\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t80\t92\t97.0\t30.0\t92.0\t83.0\t98\t36\t6\t23\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t23\t96\t67.0\t41.0\t8.0\t20.0\t97\t57\t59\t23\n" ] } ], "source": [ "fmrib_unpack -s 2:2:10 out.tsv data_01.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "e553dda7-a3dc-4912-a1c5-974a95e915df", "metadata": {}, "source": [ "#### Selecting subjects from a file" ] }, { "cell_type": "code", "execution_count": 13, "id": "422b9fae-450a-4a57-bb9c-a371cb3336c7", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:08.012882Z", "iopub.status.busy": "2026-06-15T10:54:08.012795Z", "iopub.status.idle": "2026-06-15T10:54:08.512750Z", "shell.execute_reply": "2026-06-15T10:54:08.512327Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\t4-0.0\t5-0.0\t6-0.0\t7-0.0\t8-0.0\t9-0.0\t10-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t8\t86\t51.0\t68.0\t80.0\t84.0\t11\t28\t69\t10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t6\t29\t85.0\t59.0\t7.0\t46.0\t14\t60\t73\t80\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t24\t49\t41.0\t46.0\t92.0\t23.0\t39\t68\t7\t63\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t80\t92\t97.0\t30.0\t92.0\t83.0\t98\t36\t6\t23\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t84\t59\t89.0\t79.0\t16.0\t12.0\t95\t73\t2\t62\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t23\t96\t67.0\t41.0\t8.0\t20.0\t97\t57\t59\t23\n" ] } ], "source": [ "echo -e \"5\\n6\\n7\\n8\\n9\\n10\" > subjects.txt\n", "fmrib_unpack -s subjects.txt out.tsv data_01.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "bae852d5-6da1-46bd-8643-366aaa7a9f1e", "metadata": {}, "source": [ "#### Selecting subjects by data-field value\n", "\n", "The `--subject` option accepts *data-field expressions* (a.k.a *variable\n", "expressiones*)- you can write an expression performing numerical\n", "comparisons on data-fields (denoted with a leading `v`) and combine these\n", "expressions using boolean algebra. Only subjects for which the expression\n", "evaluates to true will be imported. For example, to only import subjects\n", "where data-field 1 is greater than 10, and data-field 2 is less than 70,\n", "you can type:" ] }, { "cell_type": "code", "execution_count": 14, "id": "bdacf87f-fa0f-45ed-9439-60f0939ea4cb", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:08.513704Z", "iopub.status.busy": "2026-06-15T10:54:08.513622Z", "iopub.status.idle": "2026-06-15T10:54:08.947638Z", "shell.execute_reply": "2026-06-15T10:54:08.947130Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\t4-0.0\t5-0.0\t6-0.0\t7-0.0\t8-0.0\t9-0.0\t10-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t31\t65\t10.0\t11.0\t84.0\t22.0\t56\t65\t90\t12\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t56\t52\t52.0\t42.0\t89.0\t35.0\t3\t65\t50\t67\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t24\t49\t41.0\t46.0\t92.0\t23.0\t39\t68\t7\t63\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t84\t59\t89.0\t79.0\t16.0\t12.0\t95\t73\t2\t62\n" ] } ], "source": [ "fmrib_unpack -s \"v1 > 10 && v2 < 70\" out.tsv data_01.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "caf3fa7b-0f29-4ace-a9e8-1a0419eb3bd6", "metadata": {}, "source": [ "The following symbols can be used in data-field expressions:\n", "\n", "| Symbol | Meaning |\n", "|------------|---------------------------------|\n", "| `==` | equal to |\n", "| `!=` | not equal to |\n", "| `>` | greater than |\n", "| `>=` | greater than or equal to |\n", "| `<` | less than |\n", "| `<=` | less than or equal to |\n", "| `na` | N/A |\n", "| `&&` | logical and |\n", "| `||` | logical or |\n", "| `~` | logical not |\n", "| `contains` | Contains sub-string |\n", "| `all` | all columns must meet condition |\n", "| `any` | any column must meet condition |\n", "| `()` | to denote precedence |\n", "\n", "> The `all` and `any` symbols allow you to control how an expression is\n", "> evaluated across multiple columns which are associated with one data-field\n", "> (e.g.\u00a0separate columns for each visit). We will give an example of this in\n", "> the section on [selecting visits](#Selecting-visits), below.\n", "\n", "Non-numeric (i.e.\u00a0string) data-fields can be used in these expressions in\n", "conjunction with the `==`, `!=`, and `contains` operators, and date/time\n", "data-fields can be compared using the `==`, `!=`, `>`, `>=`, `<`, and `<=`\n", "operators. For example, imagine that we have the following data set:" ] }, { "cell_type": "code", "execution_count": 15, "id": "98b746f3-a825-4bf2-adf4-ddcc3511b845", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:08.948624Z", "iopub.status.busy": "2026-06-15T10:54:08.948544Z", "iopub.status.idle": "2026-06-15T10:54:09.059823Z", "shell.execute_reply": "2026-06-15T10:54:09.059210Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t33-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\tA\t1948-07-14\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\tB\t1954-11-18\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\tB\t1977-09-16\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\tA\t1962-04-26\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\tB\t1945-02-08\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\tA\t1978-07-24\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\tB\t1950-07-25\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\tA\t1965-07-25\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\tB\t1967-07-16\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\tA\t1950-11-16\n" ] } ], "source": [ "cat data_02.tsv" ] }, { "cell_type": "markdown", "id": "3e54cd6b-f070-4aa1-8e20-1df3cd68aa81", "metadata": {}, "source": [ "And we want to identify subjects who were born during or after 1965 (data-field\n", "33), and who have a value of `B` for data-field 1:" ] }, { "cell_type": "code", "execution_count": 16, "id": "510fd8a9-3ef2-4884-8bb2-e13e34b5aeb5", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:09.061117Z", "iopub.status.busy": "2026-06-15T10:54:09.060980Z", "iopub.status.idle": "2026-06-15T10:54:09.504716Z", "shell.execute_reply": "2026-06-15T10:54:09.504426Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t33-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\tB\t1977-09-16\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\tB\t1967-07-16\n" ] } ], "source": [ "fmrib_unpack -s \"v33 >= 1965-01-01 && v1 == 'B'\" out.tsv data_02.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "02f57172-27c5-4e7b-a593-c84d7289bb04", "metadata": {}, "source": [ "> When comparing dates and times, you must use the format `YYYY-MM-DD` and\n", "> `YYYY-MM-DD HH:MM:SS` respectively. When comparing strings, you must surround\n", "> values with single or double quotes.\n", "\n", "Evaluating a data-field expression requires the data for every subject to be\n", "loaded into memory, so that the conditional expression can be evaluated, which\n", "can be problematic on systems with limited RAM.\n", "\n", "A useful strategy, if you intend to work with the same subset of subjects more\n", "than once, is to use FUNPACK once, to identify the subjects of interest, save\n", "their IDs to a text file (e.g.\u00a0`subjects.txt`), and on subsequent calls to\n", "FUNPACK, use the text file to select subjects (e.g.\u00a0`fmrib_unpack -s subjects.txt`). This means that subsequent FUNPACK runs will require less\n", "memory, and run much faster.\n", "\n", "The `--ids_only` option can be used to generate an output file which only\n", "contains the IDs of the rows which would have been output, so can be used to\n", "generate a subject ID file. Let\u2019s re-run one of the examples above, but this\n", "time with the `--ids_only` option:" ] }, { "cell_type": "code", "execution_count": 17, "id": "712fc4d8-50d8-4e73-92c2-08574885abeb", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:09.505799Z", "iopub.status.busy": "2026-06-15T10:54:09.505731Z", "iopub.status.idle": "2026-06-15T10:54:09.945676Z", "shell.execute_reply": "2026-06-15T10:54:09.945134Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\n" ] } ], "source": [ "fmrib_unpack --ids_only -v 1,2 -s \"v1 > 10 && v2 < 70\" subjects.txt data_01.tsv\n", "cat subjects.txt" ] }, { "cell_type": "markdown", "id": "b96233de-6910-4aae-85e2-4d29cca9729e", "metadata": {}, "source": [ "Now we can use `subjects.txt` with the `-s` option in subsequent FUNPACK\n", "calls, to select the same subjects without having to re-evaluate the data-field\n", "expression.\n", "\n", "#### Excluding subjects\n", "\n", "The `--exclude` (`-ex` for short) option allows you to exclude subjects - it\n", "accepts individual IDs, an ID range, or a file containing IDs. The\n", "`--exclude`/`-ex` option takes precedence over the `--subject`/`-s` option:" ] }, { "cell_type": "code", "execution_count": 18, "id": "ddef115d-b7fd-4014-a49b-d28efa3a8efc", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:09.946692Z", "iopub.status.busy": "2026-06-15T10:54:09.946607Z", "iopub.status.idle": "2026-06-15T10:54:10.393328Z", "shell.execute_reply": "2026-06-15T10:54:10.392799Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\t4-0.0\t5-0.0\t6-0.0\t7-0.0\t8-0.0\t9-0.0\t10-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t31\t65\t10.0\t11.0\t84.0\t22.0\t56\t65\t90\t12\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t56\t52\t52.0\t42.0\t89.0\t35.0\t3\t65\t50\t67\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t45\t84\t20.0\t84.0\t93.0\t36.0\t96\t62\t48\t59\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t7\t46\t37.0\t48.0\t80.0\t20.0\t18\t72\t37\t27\n" ] } ], "source": [ "fmrib_unpack -s 1:8 -ex 5:10 out.tsv data_01.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "978c9162-8891-42b7-91ca-5599ef4471cd", "metadata": {}, "source": [ "### Selecting visits\n", "\n", "Many data-fields in the UK Biobank data contain observations at multiple points\n", "in time, or visits. FUNPACK allows you to specify which visits you are\n", "interested in. Here is an example data set with data-fields that have data for\n", "multiple visits (remember that the second number in the column names denotes\n", "the visit):" ] }, { "cell_type": "code", "execution_count": 19, "id": "94a891af-fc5b-4723-819c-be33b99b2840", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:10.394270Z", "iopub.status.busy": "2026-06-15T10:54:10.394185Z", "iopub.status.idle": "2026-06-15T10:54:10.504319Z", "shell.execute_reply": "2026-06-15T10:54:10.503772Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t2-1.0\t2-2.0\t3-0.0\t3-1.0\t4-0.0\t5-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t86\t76\t82\t75\t34\t99\t50\t5\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t20\t25\t40\t44\t30\t57\t54\t44\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t85\t2\t48\t42\t23\t77\t84\t27\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t23\t30\t18\t97\t44\t55\t97\t20\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t83\t45\t76\t51\t18\t64\t8\t33\n" ] } ], "source": [ "cat data_03.tsv" ] }, { "cell_type": "markdown", "id": "664a1b19-c103-4634-b0f2-c17b728ea131", "metadata": {}, "source": [ "We can use the `--visit` (`-vi` for short) option to get just the last visit for\n", "each data-field:" ] }, { "cell_type": "code", "execution_count": 20, "id": "1c47e346-24cb-4340-94c5-b359f2967196", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:10.505857Z", "iopub.status.busy": "2026-06-15T10:54:10.505760Z", "iopub.status.idle": "2026-06-15T10:54:10.960956Z", "shell.execute_reply": "2026-06-15T10:54:10.960562Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-2.0\t3-1.0\t4-0.0\t5-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t86\t75\t99.0\t50.0\t5.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t20\t44\t57.0\t54.0\t44.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t85\t42\t77.0\t84.0\t27.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t23\t97\t55.0\t97.0\t20.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t83\t51\t64.0\t8.0\t33.0\n" ] } ], "source": [ "fmrib_unpack -vi last out.tsv data_03.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "3953e4fa-1383-4076-b15b-ea637b2134bd", "metadata": {}, "source": [ "You can also specify which visit you want by its number:" ] }, { "cell_type": "code", "execution_count": 21, "id": "32450388-5591-4efa-8802-655be8b4c816", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:10.961942Z", "iopub.status.busy": "2026-06-15T10:54:10.961861Z", "iopub.status.idle": "2026-06-15T10:54:11.417225Z", "shell.execute_reply": "2026-06-15T10:54:11.416778Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t2-1.0\t3-1.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t82\t99.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t40\t57.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t48\t77.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t18\t55.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t76\t64.0\n" ] } ], "source": [ "fmrib_unpack -vi 1 out.tsv data_03.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "79b5824b-0441-44e7-a1de-4c9d8d3af730", "metadata": {}, "source": [ "> Data-fields which are not associated with specific visits (e.g.\u00a0[ICD10\n", "> diagnosis codes](https://biobank.ctsu.ox.ac.uk/crystal/field.cgi?id=41202))\n", "> will not be affected by the `-vi` option. Specifically, the `-vi` option is\n", "> only applied to data-fields which use an\n", "> [\u201cinstancing\u201d](https://biobank.ctsu.ox.ac.uk/crystal/help.cgi?cd=instances)\n", "> of [2 (Assessment Centre\n", "> Visit)](https://biobank.ctsu.ox.ac.uk/crystal/instance.cgi?id=2).\n", "\n", "#### Evaluating expressions across visits\n", "\n", "The data-field expressions described above in the section on [selecting\n", "subjects](#Selecting-subjects-by-data-field-value) will be applied to all of\n", "the columns associated with a data-field. By default, an expression will\n", "evaluate to true where the values in *any* column asssociated with the\n", "data-field evaluate to true. For example, we can extract the data for subjects\n", "where the values of any column of data-field 2 were less than 50:" ] }, { "cell_type": "code", "execution_count": 22, "id": "7b9b2de7-0ced-4659-83f1-33fb9d98e22a", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:11.418244Z", "iopub.status.busy": "2026-06-15T10:54:11.418161Z", "iopub.status.idle": "2026-06-15T10:54:11.870586Z", "shell.execute_reply": "2026-06-15T10:54:11.870154Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t2-0.0\t2-1.0\t2-2.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t25\t40\t44\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t2\t48\t42\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t30\t18\t97\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t45\t76\t51\n" ] } ], "source": [ "fmrib_unpack -v 2 -s 'v2 < 50' out.tsv data_03.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "6a95c8bd-fdf0-4adb-8fc9-e4df717dbde7", "metadata": {}, "source": [ "We can use the `any` and `all` operators to control how an expression is\n", "evaluated across the columns of a data-field. For example, we may only be\n", "interested in subjects for whom all columns of data-field 2 were greater than\n", "50:" ] }, { "cell_type": "code", "execution_count": 23, "id": "f4c27f6f-2321-4e02-afe7-4be6e10bb876", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:11.871570Z", "iopub.status.busy": "2026-06-15T10:54:11.871496Z", "iopub.status.idle": "2026-06-15T10:54:12.342787Z", "shell.execute_reply": "2026-06-15T10:54:12.342395Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t2-0.0\t2-1.0\t2-2.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t25\t40\t44\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t2\t48\t42\n" ] } ], "source": [ "fmrib_unpack -v 2 -s 'all(v2 < 50)' out.tsv data_03.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "2487ee06-f2ff-4fb2-8a91-dcb0ed3e080e", "metadata": {}, "source": [ "We can use `any` and `all` in expressions involving multiple data-fields:" ] }, { "cell_type": "code", "execution_count": 24, "id": "6e351647-3c7f-40cb-83cb-db98465a3f7e", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:12.343571Z", "iopub.status.busy": "2026-06-15T10:54:12.343507Z", "iopub.status.idle": "2026-06-15T10:54:12.822191Z", "shell.execute_reply": "2026-06-15T10:54:12.821783Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t2-0.0\t2-1.0\t2-2.0\t3-0.0\t3-1.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t30\t18\t97\t44.0\t55.0\n" ] } ], "source": [ "fmrib_unpack -v 2,3 -s 'any(v2 < 50) && all(v3 >= 40)' out.tsv data_03.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "36369377-00f7-4152-b1a2-9825d38d49df", "metadata": {}, "source": [ "### Merging multiple input files\n", "\n", "If your data is split across multiple files, you can specify how FUNPACK\n", "should merge them together.\n", "\n", "#### Merging two UK Biobank data sets with a bridge file\n", "\n", "Every UK Biobank application is assigned a different set of subject IDs,\n", "for anonymisation/privacy purposes. Some researchers are part of multiple\n", "applications, and occasionally need to work with data from both applications.\n", "To facilitate this, the UK Biobank may provide these researchers with a\n", "*bridge* file which contains a mapping between the subject IDs from both\n", "applications. You can use FUNPACK to merge two data sets together with a\n", "bridge file.\n", "\n", "For example, let\u2019s say we have two input files (shown side-by-side) with\n", "different sets of subject IDs:" ] }, { "cell_type": "code", "execution_count": 25, "id": "5852fd8d-13c1-4133-957b-1462ebe4df5a", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:12.822998Z", "iopub.status.busy": "2026-06-15T10:54:12.822930Z", "iopub.status.idle": "2026-06-15T10:54:12.939134Z", "shell.execute_reply": "2026-06-15T10:54:12.938796Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\t \teid\t4-0.0\t5-0.0\t6-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t89\t47\t26\t\t100\t28\t78\t89\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t94\t37\t70\t\t200\t42\t13\t70\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t63\t5\t97\t\t300\t17\t79\t86\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t98\t97\t91\t\t400\t60\t19\t38\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t37\t10\t11\t\t500\t26\t76\t6\n" ] } ], "source": [ "echo \" \" | paste data_04.tsv - data_04_2.tsv" ] }, { "cell_type": "markdown", "id": "ff4d27ff-4349-4af6-917d-d0d07bc8d364", "metadata": {}, "source": [ "And we have a bridge file which maps the two sets of subject IDs to each other:" ] }, { "cell_type": "code", "execution_count": 26, "id": "157cb752-e03c-4876-9db3-2fa3e7611293", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:12.940009Z", "iopub.status.busy": "2026-06-15T10:54:12.939948Z", "iopub.status.idle": "2026-06-15T10:54:13.061129Z", "shell.execute_reply": "2026-06-15T10:54:13.060785Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid1,eid2\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1,100\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2,200\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3,300\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4,400\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5,500\n" ] } ], "source": [ "cat bridge.csv" ] }, { "cell_type": "markdown", "id": "9aa05146-fefe-49a0-bb0c-a85612d1f021", "metadata": {}, "source": [ "We can merge these two datasets together by running FUNPACK twice - first, we\n", "will merge the bridge file and the second data set together. We use the\n", "`--index ` option to tell FUNPACK to use the second set of\n", "subject IDs from the bridge file." ] }, { "cell_type": "code", "execution_count": 27, "id": "3b868a32-2cee-433a-9e39-33e84a507a89", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:13.061951Z", "iopub.status.busy": "2026-06-15T10:54:13.061880Z", "iopub.status.idle": "2026-06-15T10:54:13.528228Z", "shell.execute_reply": "2026-06-15T10:54:13.527859Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid2\teid1\t4-0.0\t5-0.0\t6-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "100\t1\t28.0\t78.0\t89.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "200\t2\t42.0\t13.0\t70.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "300\t3\t17.0\t79.0\t86.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "400\t4\t60.0\t19.0\t38.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "500\t5\t26.0\t76.0\t6.0\n" ] } ], "source": [ "fmrib_unpack --index bridge.csv 1 temp.tsv bridge.csv data_04_2.tsv\n", "cat temp.tsv" ] }, { "cell_type": "markdown", "id": "2c0a60c0-d385-47e6-ac73-57046c0a233c", "metadata": {}, "source": [ "Then we can run FUNPACK again to merge in the first data set. This time, we\n", "use the `--index ` again to tell FUNPACK to use the *first*\n", "set of subject IDs from the intermediate file." ] }, { "cell_type": "code", "execution_count": 28, "id": "e26f1d65-737b-4481-b421-9f59de629c46", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:13.529005Z", "iopub.status.busy": "2026-06-15T10:54:13.528935Z", "iopub.status.idle": "2026-06-15T10:54:13.959561Z", "shell.execute_reply": "2026-06-15T10:54:13.959144Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\teid2\t4-0.0\t5-0.0\t6-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t89\t47\t26.0\t100\t28.0\t78.0\t89.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t94\t37\t70.0\t200\t42.0\t13.0\t70.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t63\t5\t97.0\t300\t17.0\t79.0\t86.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t98\t97\t91.0\t400\t60.0\t19.0\t38.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t37\t10\t11.0\t500\t26.0\t76.0\t6.0\n" ] } ], "source": [ "fmrib_unpack --index temp.tsv 1 out.tsv data_04.tsv temp.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "30b0a4af-a78f-4cda-b809-13a7e1c4c80a", "metadata": {}, "source": [ "FUNPACK also has more flexible options for merging datasets, as outlined below.\n", "\n", "#### Merging by subject\n", "\n", "For example, let\u2019s say we have these two input files (shown side-by-side):" ] }, { "cell_type": "code", "execution_count": 29, "id": "ab693493-0896-472c-a0c2-25ad9c5b393f", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:13.960304Z", "iopub.status.busy": "2026-06-15T10:54:13.960240Z", "iopub.status.idle": "2026-06-15T10:54:14.084154Z", "shell.execute_reply": "2026-06-15T10:54:14.083776Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\t \teid\t4-0.0\t5-0.0\t6-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t89\t47\t26\t\t2\t19\t17\t62\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t94\t37\t70\t\t3\t41\t12\t7\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t63\t5\t97\t\t4\t8\t86\t9\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t98\t97\t91\t\t5\t7\t65\t71\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t37\t10\t11\t\t6\t3\t23\t15\n" ] } ], "source": [ "echo \" \" | paste data_04.tsv - data_05.tsv" ] }, { "cell_type": "markdown", "id": "9bbd05ad-7b9f-4ab1-a771-24e07427398e", "metadata": {}, "source": [ "Note that each file contains different data-fields, and different, but\n", "overlapping, subjects. By default, when you pass these files to FUNPACK, it\n", "will output the intersection of the two files (more formally known as an\n", "*inner join*), i.e.\u00a0subjects which are present in both files:" ] }, { "cell_type": "code", "execution_count": 30, "id": "830be4df-3fc0-4523-a1a8-e569da16a8a6", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:14.084879Z", "iopub.status.busy": "2026-06-15T10:54:14.084824Z", "iopub.status.idle": "2026-06-15T10:54:14.539175Z", "shell.execute_reply": "2026-06-15T10:54:14.538807Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\t4-0.0\t5-0.0\t6-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t94\t37\t70.0\t19.0\t17.0\t62.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t63\t5\t97.0\t41.0\t12.0\t7.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t98\t97\t91.0\t8.0\t86.0\t9.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t37\t10\t11.0\t7.0\t65.0\t71.0\n" ] } ], "source": [ "fmrib_unpack out.tsv data_04.tsv data_05.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "f3bbf660-99c8-4c5d-b5a5-cf4e35b2be26", "metadata": {}, "source": [ "If you want to keep all subjects, you can instruct FUNPACK to output the union\n", "(a.k.a. *outer join*) via the `--merge_strategy` (`-ms` for short) option:" ] }, { "cell_type": "code", "execution_count": 31, "id": "fe9fee5f-3c69-46d5-b625-49bc147acf28", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:14.540005Z", "iopub.status.busy": "2026-06-15T10:54:14.539938Z", "iopub.status.idle": "2026-06-15T10:54:15.006175Z", "shell.execute_reply": "2026-06-15T10:54:15.005830Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\t4-0.0\t5-0.0\t6-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t89.0\t47.0\t26.0\t\t\t\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t94.0\t37.0\t70.0\t19.0\t17.0\t62.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t63.0\t5.0\t97.0\t41.0\t12.0\t7.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t98.0\t97.0\t91.0\t8.0\t86.0\t9.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t37.0\t10.0\t11.0\t7.0\t65.0\t71.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t\t\t\t3.0\t23.0\t15.0\n" ] } ], "source": [ "fmrib_unpack -ms outer out.tsv data_04.tsv data_05.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "dc7e9c63-6cd8-4824-bafe-d79c764b6f00", "metadata": {}, "source": [ "#### Merging by column\n", "\n", "Your data may be organised in a different way. For example, these next two\n", "files contain different groups of subjects, but overlapping columns:" ] }, { "cell_type": "code", "execution_count": 32, "id": "4060f334-5fc4-49df-bf9a-bbb97face95a", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:15.006975Z", "iopub.status.busy": "2026-06-15T10:54:15.006899Z", "iopub.status.idle": "2026-06-15T10:54:15.131218Z", "shell.execute_reply": "2026-06-15T10:54:15.130785Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\t4-0.0\t5-0.0\t \teid\t2-0.0\t3-0.0\t4-0.0\t5-0.0\t6-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t69\t80\t70\t60\t42\t\t4\t17\t36\t56\t90\t12\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t64\t15\t82\t99\t67\t\t5\t63\t16\t87\t57\t63\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t33\t67\t58\t96\t26\t\t6\t43\t19\t84\t53\t63\n" ] } ], "source": [ "echo \" \" | paste data_06.tsv - data_07.tsv" ] }, { "cell_type": "markdown", "id": "628628a3-05bf-406b-8e69-157d69bc45e5", "metadata": {}, "source": [ "In this case, we need to tell FUNPACK to merge along the row axis, rather than\n", "along the column axis. We can do this with the `--merge_axis` (`-ma` for short)\n", "option:" ] }, { "cell_type": "code", "execution_count": 33, "id": "c684034d-1c58-4fe9-991f-bc866070492b", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:15.131914Z", "iopub.status.busy": "2026-06-15T10:54:15.131843Z", "iopub.status.idle": "2026-06-15T10:54:15.618143Z", "shell.execute_reply": "2026-06-15T10:54:15.617760Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t2-0.0\t3-0.0\t4-0.0\t5-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t80\t70.0\t60.0\t42.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t15\t82.0\t99.0\t67.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t67\t58.0\t96.0\t26.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t17\t36.0\t56.0\t90.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t63\t16.0\t87.0\t57.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t43\t19.0\t84.0\t53.0\n" ] } ], "source": [ "fmrib_unpack -ma rows out.tsv data_06.tsv data_07.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "23aeb123-eda3-4aa7-9157-4780811abc59", "metadata": {}, "source": [ "Again, if we want to retain all columns, we can tell FUNPACK to perform an\n", "outer join with the `-ms` option:" ] }, { "cell_type": "code", "execution_count": 34, "id": "9779f961-2ccf-49de-bc5a-8ea3c930718f", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:15.619003Z", "iopub.status.busy": "2026-06-15T10:54:15.618937Z", "iopub.status.idle": "2026-06-15T10:54:16.084202Z", "shell.execute_reply": "2026-06-15T10:54:16.083791Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\t4-0.0\t5-0.0\t6-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t69.0\t80\t70.0\t60.0\t42.0\t\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t64.0\t15\t82.0\t99.0\t67.0\t\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t33.0\t67\t58.0\t96.0\t26.0\t\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t\t17\t36.0\t56.0\t90.0\t12.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t\t63\t16.0\t87.0\t57.0\t63.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t\t43\t19.0\t84.0\t53.0\t63.0\n" ] } ], "source": [ "fmrib_unpack -ma rows -ms outer out.tsv data_06.tsv data_07.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "be35addc-8dba-4e0d-8575-c4a215792b88", "metadata": {}, "source": [ "#### Naive merging\n", "\n", "Finally, your data may be organised such that you simply want to \u201cpaste\u201d, or\n", "concatenate them together, along either rows or columns. For example, your\n", "data files might look like this:" ] }, { "cell_type": "code", "execution_count": 35, "id": "2adc8c3c-d60b-49a2-b11d-957b9b977950", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:16.084956Z", "iopub.status.busy": "2026-06-15T10:54:16.084887Z", "iopub.status.idle": "2026-06-15T10:54:16.195719Z", "shell.execute_reply": "2026-06-15T10:54:16.195390Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\t \teid\t4-0.0\t5-0.0\t6-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t30\t99\t57\t\t1\t16\t54\t60\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t3\t6\t75\t\t2\t43\t59\t9\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t13\t91\t36\t\t3\t71\t73\t38\n" ] } ], "source": [ "echo \" \" | paste data_08.tsv - data_09.tsv" ] }, { "cell_type": "markdown", "id": "b50df54a-fd6c-4481-a90b-7fce122321a1", "metadata": {}, "source": [ "Here, we have columns for different data-fields on the same set of subjects,\n", "and we just need to concatenate them together horizontally. We do this by using\n", "`--merge_strategy naive` (`-ms naive` for short):" ] }, { "cell_type": "code", "execution_count": 36, "id": "38d1eda1-b0c8-47df-b565-cca708365c63", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:16.196414Z", "iopub.status.busy": "2026-06-15T10:54:16.196357Z", "iopub.status.idle": "2026-06-15T10:54:16.657493Z", "shell.execute_reply": "2026-06-15T10:54:16.657144Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\t4-0.0\t5-0.0\t6-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t30\t99\t57.0\t16.0\t54.0\t60.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t3\t6\t75.0\t43.0\t59.0\t9.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t13\t91\t36.0\t71.0\t73.0\t38.0\n" ] } ], "source": [ "fmrib_unpack -ms naive out.tsv data_08.tsv data_09.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "1f28a016-0a3b-433a-8eec-5dbab902f5dd", "metadata": {}, "source": [ "For files which need to be concatenated vertically, such as these:" ] }, { "cell_type": "code", "execution_count": 37, "id": "f456d45d-a4be-49b8-82dd-0aace245c80d", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:16.658253Z", "iopub.status.busy": "2026-06-15T10:54:16.658174Z", "iopub.status.idle": "2026-06-15T10:54:16.765751Z", "shell.execute_reply": "2026-06-15T10:54:16.765388Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\t \teid\t1-0.0\t2-0.0\t3-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t16\t34\t10\t\t4\t40\t89\t58\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t62\t78\t16\t\t5\t25\t75\t9\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t72\t29\t53\t\t6\t28\t74\t57\n" ] } ], "source": [ "echo \" \" | paste data_10.tsv - data_11.tsv" ] }, { "cell_type": "markdown", "id": "04160d9a-1070-4024-ae7f-20f26b9b34b1", "metadata": {}, "source": [ "We need to tell FUNPACK which axis to concatenate along, again using the `-ma`\n", "option:" ] }, { "cell_type": "code", "execution_count": 38, "id": "046cdfcc-35b8-438e-8f5f-9b48cc58bedc", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:16.766439Z", "iopub.status.busy": "2026-06-15T10:54:16.766378Z", "iopub.status.idle": "2026-06-15T10:54:17.221569Z", "shell.execute_reply": "2026-06-15T10:54:17.221183Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t16\t34\t10.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t62\t78\t16.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t72\t29\t53.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t40\t89\t58.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t25\t75\t9.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t28\t74\t57.0\n" ] } ], "source": [ "fmrib_unpack -ms naive -ma rows out.tsv data_10.tsv data_11.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "87fcbc79-ca1c-4300-83b4-fb68dce214b4", "metadata": {}, "source": [ "## Cleaning examples\n", "\n", "Once the data has been imported, a set of cleaning steps are applied to each\n", "column.\n", "\n", "### NA insertion\n", "\n", "For some data-fields it may make sense to discard or ignore certain values. For\n", "example, if an individual selects *Do not know* to a question such as *How\n", "much milk did you drink yesterday?*, that answer will be coded with a specific\n", "value (e.g.\u00a0`-1`). It does not make any sense to include these values in most\n", "analyses, so FUNPACK can be used to mark such values as *Not Available\n", "(NA)*.\n", "\n", "A large number of NA insertion rules, specific to UK Biobank data-fields, are\n", "coded into FUNPACK, and are applied when you use the `-cfg fmrib` option\n", "(see the section below on [built-in rules](#Built-in-rules)). You can also\n", "specify your own rules via the `--na_values` (`-nv` for short) option.\n", "\n", "Let\u2019s say we have this data set:" ] }, { "cell_type": "code", "execution_count": 39, "id": "efc33f8d-ff8d-4a3b-b897-ee286a3319d7", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:17.222312Z", "iopub.status.busy": "2026-06-15T10:54:17.222241Z", "iopub.status.idle": "2026-06-15T10:54:17.334736Z", "shell.execute_reply": "2026-06-15T10:54:17.334389Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t4\t1\t6\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t2\t6\t0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t7\t0\t-1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t-1\t6\t1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t2\t8\t4\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t0\t2\t7\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t-1\t0\t0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t7\t7\t2\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t4\t-1\t-1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t8\t-1\t2\n" ] } ], "source": [ "cat data_12.tsv" ] }, { "cell_type": "markdown", "id": "7dde0f54-b3bc-4d3e-a0b3-a1ebc886965b", "metadata": {}, "source": [ "For data-field 1, we want to ignore values of -1, for data-field 2 we want to\n", "ignore -1 and 0, and for data-field 3 we want to ignore 1 and 2:" ] }, { "cell_type": "code", "execution_count": 40, "id": "1bb24fd7-6047-43e1-b47d-edd68fbdd8aa", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:17.335424Z", "iopub.status.busy": "2026-06-15T10:54:17.335370Z", "iopub.status.idle": "2026-06-15T10:54:17.788703Z", "shell.execute_reply": "2026-06-15T10:54:17.788336Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t4.0\t1.0\t6.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t2.0\t6.0\t0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t7.0\t\t-1.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t\t6.0\t\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t2.0\t8.0\t4.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t0.0\t2.0\t7.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t\t\t0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t7.0\t7.0\t\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t4.0\t\t-1.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t8.0\t\t\n" ] } ], "source": [ "fmrib_unpack -nv 1 \" -1\" -nv 2 \" -1,0\" -nv 3 \"1,2\" out.tsv data_12.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "0b720e3b-e3b2-4cf4-b952-e29b42804eb7", "metadata": {}, "source": [ "The `--na_values` option expects two arguments:\n", "\n", "- The data-field ID\n", "- A comma-separated list of values to replace with NA\n", "\n", "### Data-field-specific cleaning functions\n", "\n", "A small number of cleaning/preprocessing functions are built into FUNPACK,\n", "which can be applied to specific data-fields. For example, some data-fields in\n", "the UK Biobank contain ICD10 disease codes, which may be more useful if\n", "converted to a numeric format (e.g.\u00a0to make them easy to load into MATLAB).\n", "Imagine that we have some data with ICD10 codes:" ] }, { "cell_type": "code", "execution_count": 41, "id": "39907bee-ae69-4705-832a-f1f437462c41", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:17.789432Z", "iopub.status.busy": "2026-06-15T10:54:17.789370Z", "iopub.status.idle": "2026-06-15T10:54:17.908668Z", "shell.execute_reply": "2026-06-15T10:54:17.908289Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\tA481\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\tA590\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\tB391\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\tD596\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\tZ980\n" ] } ], "source": [ "cat data_13.tsv" ] }, { "cell_type": "markdown", "id": "0c9c35c8-6624-4b80-a5cb-79eba4159083", "metadata": {}, "source": [ "We can use the `--clean` (`-cl` for short) option with the built-in\n", "`codeToNumeric` cleaning function to convert the codes to a numeric\n", "representation&:" ] }, { "cell_type": "code", "execution_count": 42, "id": "8aadfb9c-4508-4ecd-8333-91ab343f0b7c", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:17.909404Z", "iopub.status.busy": "2026-06-15T10:54:17.909336Z", "iopub.status.idle": "2026-06-15T10:54:18.423628Z", "shell.execute_reply": "2026-06-15T10:54:18.423287Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t5340\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t5960\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t9320\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t21590\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t191430\n" ] } ], "source": [ "fmrib_unpack -cl 1 \"codeToNumeric('icd10')\" out.tsv data_13.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "35b4661e-ded3-4b8e-b9e8-15e2c7fb0b47", "metadata": {}, "source": [ "> &The `codeToNumeric` function will replace each ICD10 code\n", "> with the corresponding *Node* number, as defined in the UK [Biobank ICD10\n", "> data coding](http://biobank.ctsu.ox.ac.uk/crystal/coding.cgi?id=19).\n", "\n", "The `--clean` option expects two arguments:\n", "\n", "- The data-field ID\n", "- The cleaning function to apply. Some cleaning functions accept arguments -\n", " refer to the [command-line help](command_line.html) or the page on\n", " [cleaning and processing functions](function_reference.html) for a\n", " summary of available functions.\n", "\n", "You can find a list of the built-in cleaning functions\n", "[here](function_reference.html). You can also define your own cleaning\n", "functions by passing them in as a `--plugin_file` (see the [section on custom\n", "plugins below](#Custom-cleaning,-processing-and-loading---FUNPACK-plugins)).\n", "\n", "#### Example: flattening hierarchical data\n", "\n", "Several data-fields in the UK Biobank (including the ICD10 disease\n", "categorisations) are organised in a hierarchical manner - each value is a\n", "child of a more general parent category. The `flattenHierarchical` cleaninng\n", "function can be used to replace each value in a data set with the value that\n", "corresponds to a parent category. Let\u2019s apply this to our example ICD10 data\n", "set." ] }, { "cell_type": "code", "execution_count": 43, "id": "bc78ee79-31fb-4565-b293-2cbcebe1693f", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:18.424396Z", "iopub.status.busy": "2026-06-15T10:54:18.424333Z", "iopub.status.idle": "2026-06-15T10:54:18.896782Z", "shell.execute_reply": "2026-06-15T10:54:18.896333Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\tChapter I\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\tChapter I\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\tChapter I\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\tChapter III\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\tChapter XXI\n" ] } ], "source": [ "fmrib_unpack -cl 1 \"flattenHierarchical(name='icd10')\" out.tsv data_13.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "69610d38-3edf-4968-ab8f-8bfe402af17e", "metadata": {}, "source": [ "#### Aside: ICD10 mapping file\n", "\n", "FUNPACK has a feature specific to these ICD10 disease categorisations - you\n", "can use the `--icd10_map_file` (`-imf` for short) option to tell FUNPACK to\n", "save a file which contains a list of all ICD10 codes that were present in the\n", "input data, and the corresponding numerical codes that FUNPACK generated:" ] }, { "cell_type": "code", "execution_count": 44, "id": "30b23ed2-7df0-44e3-8f99-cbfeb10d3f3a", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:18.897667Z", "iopub.status.busy": "2026-06-15T10:54:18.897575Z", "iopub.status.idle": "2026-06-15T10:54:19.439519Z", "shell.execute_reply": "2026-06-15T10:54:19.439265Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "code\tvalue\tdescription\tparent_descs\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "A481\t5340\tA48.1 Legionnaires' disease\t[Chapter I Certain infectious and parasitic diseases] [A30-A49 Other bacterial diseases] [A48 Other bacterial diseases, not elsewhere classified]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "A590\t5960\tA59.0 Urogenital trichomoniasis\t[Chapter I Certain infectious and parasitic diseases] [A50-A64 Infections with a predominantly sexual mode of transmission] [A59 Trichomoniasis]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "B391\t9320\tB39.1 Chronic pulmonary histoplasmosis capsulati\t[Chapter I Certain infectious and parasitic diseases] [B35-B49 Mycoses] [B39 Histoplasmosis]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "D596\t21590\tD59.6 Haemoglobinuria due to haemolysis from other external causes\t[Chapter III Diseases of the blood and blood-forming organs and certain disorders involving the immune mechanism] [D55-D59 Haemolytic anaemias] [D59 Acquired haemolytic anaemia]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Z980\t191430\tZ98.0 Intestinal bypass and anastomosis status\t[Chapter XXI Factors influencing health status and contact with health services] [Z80-Z99 Persons with potential health hazards related to family and personal history and certain conditions influencing health status] [Z98 Other postsurgical states]\n" ] } ], "source": [ "fmrib_unpack -cl 1 \"codeToNumeric('icd10')\" -imf icd10_codes.tsv out.tsv data_13.tsv\n", "cat icd10_codes.tsv" ] }, { "attachments": { "coding.png": { "image/png": "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" } }, "cell_type": "markdown", "id": "756ad4d4-d2b7-4207-a2d7-6bc9f23cdb05", "metadata": {}, "source": [ "### Categorical recoding\n", "\n", "You may have some categorical data which is coded in an awkward manner, such as\n", "in this example, which encodes the amount of some item that an individual has\n", "consumed:\n", "\n", "
\n", "\"data\n", "
data coding example
\n", "
\n", "\n", "You can use the `--recoding` (`-re` for short) option to recode data like this\n", "into something more useful. For example, given this data:" ] }, { "cell_type": "code", "execution_count": 45, "id": "e3697cd0-059f-46b4-b9ed-865718cb8d3c", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:19.440536Z", "iopub.status.busy": "2026-06-15T10:54:19.440472Z", "iopub.status.idle": "2026-06-15T10:54:19.549137Z", "shell.execute_reply": "2026-06-15T10:54:19.548624Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t555\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t444\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t2\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t300\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t444\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t2\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t2\n" ] } ], "source": [ "cat data_14.tsv" ] }, { "cell_type": "markdown", "id": "f35fa3a0-510f-47a0-bc7c-3336411519e8", "metadata": {}, "source": [ "Let\u2019s recode it to be more monotonic:" ] }, { "cell_type": "code", "execution_count": 46, "id": "73bbed78-8cf3-45d9-a884-a624b38233e0", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:19.554406Z", "iopub.status.busy": "2026-06-15T10:54:19.554239Z", "iopub.status.idle": "2026-06-15T10:54:20.001692Z", "shell.execute_reply": "2026-06-15T10:54:20.001347Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t1.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t0.5\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t0.25\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t2.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t3.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t0.25\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t2.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t2.0\n" ] } ], "source": [ "fmrib_unpack -re 1 \"300,444,555\" \"3,0.25,0.5\" out.tsv data_14.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "ccb36fb6-40fb-4bc2-a3ad-a709bc0b5e07", "metadata": {}, "source": [ "The `--recoding` option expects three arguments:\n", "\n", "- The data-field ID\n", "- A comma-separated list of the values to be replaced\n", "- A comma-separated list of the values to replace them with\n", "\n", "### Child value replacement\n", "\n", "Imagine that we have these two questions:\n", "\n", "- **1**: *Do you currently smoke cigarettes?*\n", "- **2**: *How many cigarettes did you smoke yesterday?*\n", "\n", "Now, question 2 was only asked if the answer to question 1 was *Yes*. So for\n", "all individuals who answered *No* to question 1, we will have a missing value\n", "for question 2. But for some analyses, it would make more sense to have a\n", "value of 0, rather than NA, for these subjects.\n", "\n", "FUNPACK can handle these sorts of dependencies by way of *child value\n", "replacement*. For question 2, we can define a conditional variable expression\n", "such that when both question 2 is NA and question 1 is *No*, we can insert a\n", "value of 0 into question 2.\n", "\n", "This scenario is demonstrated in this example data set (where, for\n", "question 1 values of `1` and `0` represent *Yes* and *No* respectively):" ] }, { "cell_type": "code", "execution_count": 47, "id": "8b17b1be-ef93-4bcb-b759-55a6ca7952c6", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:20.002469Z", "iopub.status.busy": "2026-06-15T10:54:20.002408Z", "iopub.status.idle": "2026-06-15T10:54:20.121604Z", "shell.execute_reply": "2026-06-15T10:54:20.121274Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t1\t7\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t1\t4\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t1\t1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t0\t\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t0\t\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t0\t\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t1\t25\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t0\t\n" ] } ], "source": [ "cat data_15.tsv" ] }, { "cell_type": "markdown", "id": "525232b8-2bbc-4be1-b16f-355055ac69a8", "metadata": {}, "source": [ "We can fill in the values for data-field 2 by using the `--child_values` (`-cv`\n", "for short) option:" ] }, { "cell_type": "code", "execution_count": 48, "id": "bc628d1b-81a9-4b2b-b8d8-4b40adbbe867", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:20.122355Z", "iopub.status.busy": "2026-06-15T10:54:20.122296Z", "iopub.status.idle": "2026-06-15T10:54:20.600182Z", "shell.execute_reply": "2026-06-15T10:54:20.599779Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t1\t7.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t1\t4.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t1\t1.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t0\t0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t0\t0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t0\t0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t1\t25.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t0\t0.0\n" ] } ], "source": [ "fmrib_unpack -cv 2 \"v1 == 0\" \"0\" out.tsv data_15.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "415ab4ef-6357-4e72-9246-900dae36072c", "metadata": {}, "source": [ "The `--child_values` option expects three arguments:\n", "\n", "- The data-field ID\n", "- An expression evaluating some condition on the parent data-field(s)\n", "- A value to replace NA with where the expression evaluates to true.\n", "\n", "## Processing examples\n", "\n", "After every column has been cleaned, the entire data set undergoes a series of\n", "processing steps. The processing stage may result in columns being removed or\n", "manipulated, or new columns being added.\n", "\n", "The processing stage can be controlled with these options:\n", "\n", "- `--prepend_process` (`-ppr` for short): Apply a processing function before\n", " the built-in processing\n", "- `--append_process` (`-apr` for short): Apply a processing function after the\n", " built-in processing\n", "\n", "A default set of processing steps are applied when you apply the `fmrib`\n", "configuration profile by using `-cfg fmrib` - see the section on [built-in\n", "rules](#Built-in-rules).\n", "\n", "The `--prepend_process` and `--append_process` options require two arguments:\n", "\n", "- The data-field ID(s) to apply the function to, or `all` to denote all\n", " variables.\n", "- The processing function to apply. The available processing functions are\n", " listed [here](function_reference.html) and in the [command line\n", " help](command_line.html), or you can write your own and pass it in as a\n", " plugin file ([see\n", " below](#Custom-cleaning,-processing-and-loading---FUNPACK-plugins)).\n", "\n", "### Sparsity check\n", "\n", "The `removeIfSparse` process will remove columns that are deemed to have too\n", "many missing values. If we take this data set:" ] }, { "cell_type": "code", "execution_count": 49, "id": "00b73094-0e2f-4c23-9af8-6ab0a5ebf0c7", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:20.601052Z", "iopub.status.busy": "2026-06-15T10:54:20.600978Z", "iopub.status.idle": "2026-06-15T10:54:20.717572Z", "shell.execute_reply": "2026-06-15T10:54:20.717235Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t7\t24\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t2\t37\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t4\t14\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t6\t\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t\t77\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t7\t10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t\t\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t3\t13\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t\t62\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t\t74\n" ] } ], "source": [ "cat data_16.tsv" ] }, { "cell_type": "markdown", "id": "d3b7abd2-a7dd-44bb-a140-af257a09d1cb", "metadata": {}, "source": [ "Imagine that our analysis requires at least 8 values per data-field to work. We\n", "can use the `minpres` option to `removeIfSparse` to drop any columns which do\n", "not meet this threshold:" ] }, { "cell_type": "code", "execution_count": 50, "id": "f5777b65-5ab4-4ac7-a297-1b2366bf6198", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:20.718320Z", "iopub.status.busy": "2026-06-15T10:54:20.718259Z", "iopub.status.idle": "2026-06-15T10:54:21.194446Z", "shell.execute_reply": "2026-06-15T10:54:21.193647Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t2-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t24.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t37.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t14.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t77.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t10.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t13.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t62.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t74.0\n" ] } ], "source": [ "fmrib_unpack -apr all \"removeIfSparse(minpres=8)\" out.tsv data_16.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "067a9c29-682e-48b5-af7d-1c3cce9b3265", "metadata": {}, "source": [ "You can also specify `minpres` as a proportion, rather than an absolute number.\n", "e.g.:" ] }, { "cell_type": "code", "execution_count": 51, "id": "288d9f84-764b-485e-aac5-3314836c8d8d", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:21.197121Z", "iopub.status.busy": "2026-06-15T10:54:21.197035Z", "iopub.status.idle": "2026-06-15T10:54:21.678708Z", "shell.execute_reply": "2026-06-15T10:54:21.678261Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t2-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t24.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t37.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t14.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t77.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t10.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t13.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t62.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t74.0\n" ] } ], "source": [ "fmrib_unpack -apr all \"removeIfSparse(minpres=0.65, abspres=False)\" out.tsv data_16.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "c62d9e5d-178a-42eb-b227-1acd2dc31ef4", "metadata": {}, "source": [ "### Redundancy check\n", "\n", "You may wish to remove columns which contain redundant information. The\n", "`removeIfRedundant` process calculates the pairwise correlation between all\n", "columns, and removes columns with a correlation above a threshold that you\n", "provide. Imagine that we have this data set:" ] }, { "cell_type": "code", "execution_count": 52, "id": "633f8ca8-cef6-41fa-a068-163c69942f59", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:21.679489Z", "iopub.status.busy": "2026-06-15T10:54:21.679416Z", "iopub.status.idle": "2026-06-15T10:54:21.792503Z", "shell.execute_reply": "2026-06-15T10:54:21.792121Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t1\t10\t1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t2\t20\t6\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t3\t30\t3\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t4\t40\t7\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t5\t50\t2\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t6\t60\t3\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t5\t50\t2\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t4\t40\t9\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t3\t30\t8\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t2\t20\t5\n" ] } ], "source": [ "cat data_17.tsv" ] }, { "cell_type": "markdown", "id": "c660c1d7-020e-4f37-acf7-fd78c93279c8", "metadata": {}, "source": [ "The data in column `2-0.0` is effectively equivalent to the data in column\n", "`1-0.0`, so is not of any use to us. We can tell FUNPACK to remove it like\n", "so:" ] }, { "cell_type": "code", "execution_count": 53, "id": "afe7d290-0365-4ddf-8021-4aaafcc01822", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:21.793289Z", "iopub.status.busy": "2026-06-15T10:54:21.793226Z", "iopub.status.idle": "2026-06-15T10:54:22.231787Z", "shell.execute_reply": "2026-06-15T10:54:22.231184Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t3-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t1\t1.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t2\t6.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t3\t3.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t4\t7.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t5\t2.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t6\t3.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t5\t2.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t4\t9.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t3\t8.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t2\t5.0\n" ] } ], "source": [ "fmrib_unpack -apr all \"removeIfRedundant(0.9)\" out.tsv data_17.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "5afd2f22-b3b7-4355-9c2d-0ee94022ffd5", "metadata": {}, "source": [ "The `removeIfRedundant` process can also calculate the correlation of the\n", "patterns of missing values between data-fields - Consider this example:" ] }, { "cell_type": "code", "execution_count": 54, "id": "ed1e4214-79ec-4b34-bdeb-b4311ea06459", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:22.233169Z", "iopub.status.busy": "2026-06-15T10:54:22.233047Z", "iopub.status.idle": "2026-06-15T10:54:22.358620Z", "shell.execute_reply": "2026-06-15T10:54:22.357014Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t1\t10\t100\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t2\t20\t200\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t\t\t300\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t4\t40\t400\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t\t\t500\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t4\t40\t\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t3\t\t300\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t2\t20\t200\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t1\t10\t100\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t\t\t0\n" ] } ], "source": [ "cat data_18.tsv" ] }, { "cell_type": "markdown", "id": "27fa3188-ba00-4398-b54c-a52d4b44f265", "metadata": {}, "source": [ "All three columns are highly correlated, but the pattern of missing values in\n", "column `3-0.0` is different to that of the other columns.\n", "\n", "If we use the `nathres` option, FUNPACK will only remove columns where the\n", "correlation of both present and missing values meet the thresholds. Note that\n", "the column which contains more missing values will be the one that gets\n", "removed:" ] }, { "cell_type": "code", "execution_count": 55, "id": "70ba21f4-1439-4e28-ac3f-087a0f2f5eb3", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:22.361243Z", "iopub.status.busy": "2026-06-15T10:54:22.361060Z", "iopub.status.idle": "2026-06-15T10:54:22.824783Z", "shell.execute_reply": "2026-06-15T10:54:22.824238Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t3-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t1.0\t100.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t2.0\t200.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t\t300.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t4.0\t400.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t\t500.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t4.0\t\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t3.0\t300.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t2.0\t200.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t1.0\t100.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t\t0.0\n" ] } ], "source": [ "fmrib_unpack -apr all \"removeIfRedundant(0.9, nathres=0.6)\" out.tsv data_18.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "5019d1fd-6dab-460c-91c1-bdb0847a5007", "metadata": {}, "source": [ "### Categorical binarisation\n", "\n", "The `binariseCategorical` process takes a column containing categorical\n", "labels, and replaces it with a set of new binary columns, one for each\n", "category. Imagine that we have this data:" ] }, { "cell_type": "code", "execution_count": 56, "id": "f121abcd-ee71-4f08-9f6c-f29c1e4aaad2", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:22.826159Z", "iopub.status.busy": "2026-06-15T10:54:22.826065Z", "iopub.status.idle": "2026-06-15T10:54:22.948517Z", "shell.execute_reply": "2026-06-15T10:54:22.946979Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid 1-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t2\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t3\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t2\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t2\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t3\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t4\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t3\n" ] } ], "source": [ "cat data_19.tsv" ] }, { "cell_type": "markdown", "id": "fa860197-88b0-4f2c-be13-a439f1a286cc", "metadata": {}, "source": [ "We can use the `binariseCategorical` process to split column `1-0.0` into a\n", "separate column for each category:" ] }, { "cell_type": "code", "execution_count": 57, "id": "8d9e81e4-ea24-4163-9758-9a699f0a399c", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:22.951100Z", "iopub.status.busy": "2026-06-15T10:54:22.950878Z", "iopub.status.idle": "2026-06-15T10:54:23.418939Z", "shell.execute_reply": "2026-06-15T10:54:23.418301Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.1\t1-0.2\t1-0.3\t1-0.4\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t1\t0\t0\t0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t0\t1\t0\t0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t0\t0\t1\t0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t0\t1\t0\t0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t0\t1\t0\t0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t0\t0\t1\t0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t1\t0\t0\t0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t0\t0\t0\t1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t1\t0\t0\t0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t0\t0\t1\t0\n" ] } ], "source": [ "fmrib_unpack -apr 1 \"binariseCategorical\" out.tsv data_19.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "640ec938-c547-48fb-9079-0912bb36dbc4", "metadata": {}, "source": [ "There are a few options to `binariseCategorical`, including controlling whether\n", "the original column is removed, and also the naming of the newly created\n", "columns:" ] }, { "cell_type": "code", "execution_count": 58, "id": "4bf42e50-2993-413d-a1a3-cfbdb26f29ef", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:23.420339Z", "iopub.status.busy": "2026-06-15T10:54:23.420219Z", "iopub.status.idle": "2026-06-15T10:54:23.855837Z", "shell.execute_reply": "2026-06-15T10:54:23.855246Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t1:1\t1:2\t1:3\t1:4\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t1\t1\t0\t0\t0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t2\t0\t1\t0\t0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t3\t0\t0\t1\t0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t2\t0\t1\t0\t0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t2\t0\t1\t0\t0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t3\t0\t0\t1\t0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t1\t1\t0\t0\t0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t4\t0\t0\t0\t1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t1\t1\t0\t0\t0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t3\t0\t0\t1\t0\n" ] } ], "source": [ "fmrib_unpack -apr 1 \"binariseCategorical(replace=False, nameFormat='{vid}:{value}')\" out.tsv data_19.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "22894523-2232-4f3b-8d2a-eed98eded935", "metadata": {}, "source": [ "## Custom cleaning, processing and loading - FUNPACK plugins\n", "\n", "If you want to apply some specific cleaning or processing function to a\n", "variable, you can code your functions up in Python, and then tell FUNPACK to\n", "apply them.\n", "\n", "As an example, let\u2019s say we have some data like this:" ] }, { "cell_type": "code", "execution_count": 59, "id": "2f0f6327-4c21-4e5a-bc35-9b6564cbac15", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:23.857038Z", "iopub.status.busy": "2026-06-15T10:54:23.856942Z", "iopub.status.idle": "2026-06-15T10:54:23.981239Z", "shell.execute_reply": "2026-06-15T10:54:23.979455Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t28\t65\t18\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t12\t71\t63\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t17\t60\t95\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t36\t80\t38\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t91\t55\t36\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t4\t97\t71\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t20\t3\t88\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t58\t64\t65\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t87\t27\t26\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t36\t17\t22\n" ] } ], "source": [ "cat data_20.tsv" ] }, { "cell_type": "markdown", "id": "2f0c1fd3-6f2f-4adf-97e0-1b8e5c8241db", "metadata": {}, "source": [ "### Custom cleaning functions\n", "\n", "But for our analysis, we are only interested in the even values for columns 1\n", "and 2. Let\u2019s write a cleaning function which replaces all odd values with NA:" ] }, { "cell_type": "code", "execution_count": 60, "id": "45d75320-91a2-4ac7-bf26-67b331d1b913", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:23.984372Z", "iopub.status.busy": "2026-06-15T10:54:23.984187Z", "iopub.status.idle": "2026-06-15T10:54:24.218827Z", "shell.execute_reply": "2026-06-15T10:54:24.218416Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m#!/usr/bin/env python\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[34mimport\u001b[39;49;00m\u001b[37m \u001b[39;49;00m\u001b[04m\u001b[36mnumpy\u001b[39;49;00m\u001b[37m \u001b[39;49;00m\u001b[34mas\u001b[39;49;00m\u001b[37m \u001b[39;49;00m\u001b[04m\u001b[36mnp\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[34mfrom\u001b[39;49;00m\u001b[37m \u001b[39;49;00m\u001b[04m\u001b[36mfunpack\u001b[39;49;00m\u001b[37m \u001b[39;49;00m\u001b[34mimport\u001b[39;49;00m cleaner\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m# Cleaner functions are passed:\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m#\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m# - dtable: An object which provides access to the data set.\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m# - vid: The variable ID of the column(s) to be cleaned.\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m#\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m# Cleaner functions should modify the data in-place.\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[90m@cleaner\u001b[39;49;00m()\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[34mdef\u001b[39;49;00m\u001b[37m \u001b[39;49;00m\u001b[32mdrop_odd_values\u001b[39;49;00m(dtable, vid):\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[37m# Remember that a variable may be\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[37m# associated with multiple columns\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " cols = dtable.columns(vid)\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[37m# the columns() method returns a list of\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[37m# Column objects, each of which contains\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[37m# information about one column in the data.\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[34mfor\u001b[39;49;00m col \u001b[35min\u001b[39;49;00m cols:\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " col = col.name\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " mask = dtable[:, col] % \u001b[34m2\u001b[39;49;00m != \u001b[34m0\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " dtable[mask, col] = np.\u001b[34mnan\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] } ], "source": [ "cat plugin_1.py | pygmentize" ] }, { "cell_type": "markdown", "id": "8edd4166-14d0-4611-8aca-ac4d4c75c132", "metadata": {}, "source": [ "To use our custom cleaner function, we simply pass our plugin file to FUNPACK\n", "using the `--plugin_file` (`-p` for short) option:" ] }, { "cell_type": "code", "execution_count": 61, "id": "efaabedd-4bb7-4011-a619-02ad377e7e38", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:24.219705Z", "iopub.status.busy": "2026-06-15T10:54:24.219636Z", "iopub.status.idle": "2026-06-15T10:54:24.690590Z", "shell.execute_reply": "2026-06-15T10:54:24.690223Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t28.0\t\t18.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t12.0\t\t63.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t\t60.0\t95.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t36.0\t80.0\t38.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t\t\t36.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t4.0\t\t71.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t20.0\t\t88.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t58.0\t64.0\t65.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t\t\t26.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t36.0\t\t22.0\n" ] } ], "source": [ "fmrib_unpack -p plugin_1.py -cl 1 drop_odd_values -cl 2 drop_odd_values out.tsv data_20.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "bd61add7-065e-4b20-a6de-3e6333c83b25", "metadata": {}, "source": [ "### Custom processing functions\n", "\n", "Recall that **cleaning** functions are applied independently to each column,\n", "whereas **processing** functions may be applied to multiple columns\n", "simultaneously, and may add and/or remove columns. Let\u2019s say we want to derive\n", "a new column from columns `1-0.0` and `2-0.0` in our example data set. Our\n", "plugin file might look like this:" ] }, { "cell_type": "code", "execution_count": 62, "id": "16735162-31d2-4265-8b58-55bd62eab264", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:24.691412Z", "iopub.status.busy": "2026-06-15T10:54:24.691339Z", "iopub.status.idle": "2026-06-15T10:54:24.912062Z", "shell.execute_reply": "2026-06-15T10:54:24.911719Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m#!/usr/bin/env python\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[34mimport\u001b[39;49;00m\u001b[37m \u001b[39;49;00m\u001b[04m\u001b[36mitertools\u001b[39;49;00m\u001b[37m \u001b[39;49;00m\u001b[34mas\u001b[39;49;00m\u001b[37m \u001b[39;49;00m\u001b[04m\u001b[36mit\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[34mfrom\u001b[39;49;00m\u001b[37m \u001b[39;49;00m\u001b[04m\u001b[36mfunpack\u001b[39;49;00m\u001b[37m \u001b[39;49;00m\u001b[34mimport\u001b[39;49;00m processor\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m# Processor functions are passed:\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m#\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m# - dtable: An object which provides access to the data set.\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m# - vid: The variable ID of the column(s) to be cleaned.\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m#\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m# Processor functions can do any of the following:\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m#\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m# - modify existing columns in place,\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m# - return a list of columns that should be removed\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m# - return a list of columns that should be added\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[90m@processor\u001b[39;49;00m()\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[34mdef\u001b[39;49;00m\u001b[37m \u001b[39;49;00m\u001b[32msum_squares\u001b[39;49;00m(dtable, vids):\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " cols = it.chain(*[dtable.columns(v) \u001b[34mfor\u001b[39;49;00m v \u001b[35min\u001b[39;49;00m vids])\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " series = [dtable[:, c.name] \u001b[34mfor\u001b[39;49;00m c \u001b[35min\u001b[39;49;00m cols]\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " squares = [s * s \u001b[34mfor\u001b[39;49;00m s \u001b[35min\u001b[39;49;00m series]\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " sumsq = \u001b[36msum\u001b[39;49;00m(squares)\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " sumsq.name = \u001b[33m'\u001b[39;49;00m\u001b[33msum_square(\u001b[39;49;00m\u001b[33m{}\u001b[39;49;00m\u001b[33m)\u001b[39;49;00m\u001b[33m'\u001b[39;49;00m.format(\u001b[33m'\u001b[39;49;00m\u001b[33m,\u001b[39;49;00m\u001b[33m'\u001b[39;49;00m.join([\u001b[36mstr\u001b[39;49;00m(v) \u001b[34mfor\u001b[39;49;00m v \u001b[35min\u001b[39;49;00m vids]))\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[37m# The value returned by a processor function differs\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[37m# depending on what it wishes to do. In this case,\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[37m# we are returning a list of new pandas.Series to be\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[37m# added as columns, and a list of integer variable\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[37m# IDs, one for each new column. The variable IDs are\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[37m# optional, so we are just returning None instead.\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[34mreturn\u001b[39;49;00m [sumsq], \u001b[34mNone\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] } ], "source": [ "cat plugin_2.py | pygmentize" ] }, { "cell_type": "markdown", "id": "553686c1-c696-482f-8a64-97e58eec55fa", "metadata": {}, "source": [ "Again, to use our plugin, we pass it to FUNPACK via the `--plugin`/`-p`\n", "option:" ] }, { "cell_type": "code", "execution_count": 63, "id": "9d8074f2-4df3-4715-a167-db10c9cfacd1", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:24.912904Z", "iopub.status.busy": "2026-06-15T10:54:24.912836Z", "iopub.status.idle": "2026-06-15T10:54:25.441700Z", "shell.execute_reply": "2026-06-15T10:54:25.441257Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\tsum_square(1,2)\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t28\t65\t18.0\t5009\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t12\t71\t63.0\t5185\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t17\t60\t95.0\t3889\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t36\t80\t38.0\t7696\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t91\t55\t36.0\t11306\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t4\t97\t71.0\t9425\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t20\t3\t88.0\t409\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t58\t64\t65.0\t7460\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t87\t27\t26.0\t8298\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t36\t17\t22.0\t1585\n" ] } ], "source": [ "fmrib_unpack -p plugin_2.py -apr \"1,2\" \"sum_squares\" out.tsv data_20.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "e9733084-aab1-4f9e-871d-0bf5941bd0cc", "metadata": {}, "source": [ "### Custom file loaders\n", "\n", "You might want to load some auxillary data which is in an awkward format that\n", "cannot be automatically parsed by FUNPACK. For example, you may have a file\n", "which has acquisition date information separated into *year*, *month* and\n", "*day* columns, e.g.:" ] }, { "cell_type": "code", "execution_count": 64, "id": "946a0434-e903-4ed8-9662-41e35e807368", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:25.442487Z", "iopub.status.busy": "2026-06-15T10:54:25.442419Z", "iopub.status.idle": "2026-06-15T10:54:25.551913Z", "shell.execute_reply": "2026-06-15T10:54:25.551621Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\tyear\tmonth\tday\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t2018\t6\t1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t2018\t6\t17\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t2018\t7\t5\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t2018\t3\t11\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t2018\t2\t21\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t2018\t8\t8\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t2018\t11\t30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t2018\t12\t5\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t2018\t4\t13\n" ] } ], "source": [ "cat data_21.tsv" ] }, { "cell_type": "markdown", "id": "bbf57216-e7bd-4315-83c6-3408955634bb", "metadata": {}, "source": [ "These three columns would be better loaded as a single column. So we can write a\n", "plugin to load this file for us. We need to write two functions:\n", "\n", "- A *sniffer* function, which returns information about the columns contained\n", " in the file.\n", "- A *loader* function which loads the file, returning it as a\n", " `pandas.DataFrame`." ] }, { "cell_type": "code", "execution_count": 65, "id": "d94bf024-68b4-4c4f-b061-97af45d741da", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:25.553661Z", "iopub.status.busy": "2026-06-15T10:54:25.553527Z", "iopub.status.idle": "2026-06-15T10:54:25.740722Z", "shell.execute_reply": "2026-06-15T10:54:25.740263Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m#!/usr/bin/env python\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[34mimport\u001b[39;49;00m\u001b[37m \u001b[39;49;00m\u001b[04m\u001b[36mpandas\u001b[39;49;00m\u001b[37m \u001b[39;49;00m\u001b[34mas\u001b[39;49;00m\u001b[37m \u001b[39;49;00m\u001b[04m\u001b[36mpd\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[34mfrom\u001b[39;49;00m\u001b[37m \u001b[39;49;00m\u001b[04m\u001b[36mfunpack\u001b[39;49;00m\u001b[37m \u001b[39;49;00m\u001b[34mimport\u001b[39;49;00m sniffer, loader, Column\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m# Sniffer and loader functions are defined in\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m# pairs. A pair is denoted by its functions\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m# being given the same label, passed to the\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m# @sniffer/@loader decorators\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m# (\"my_datefile_loader\" in this example). The\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m# function names are irrelevant.\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[90m@sniffer\u001b[39;49;00m(\u001b[33m'\u001b[39;49;00m\u001b[33mmy_datefile_loader\u001b[39;49;00m\u001b[33m'\u001b[39;49;00m)\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[34mdef\u001b[39;49;00m\u001b[37m \u001b[39;49;00m\u001b[32mcolumns_datefile\u001b[39;49;00m(infile):\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[37m# A sniifer function must return a\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[37m# sequence of Column objects which\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[37m# describe the file (after it has\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[37m# been loaded by the loader function).\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[37m#\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[37m# The values passed to a Column object\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[37m# are:\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[37m# - file name\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[37m# - column name\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[37m# - column index (starting from 0)\u001b[39;49;00m\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[34mreturn\u001b[39;49;00m [Column(infile, \u001b[33m'\u001b[39;49;00m\u001b[33meid\u001b[39;49;00m\u001b[33m'\u001b[39;49;00m, \u001b[34m0\u001b[39;49;00m),\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Column(infile, \u001b[33m'\u001b[39;49;00m\u001b[33macquisition_date\u001b[39;49;00m\u001b[33m'\u001b[39;49;00m, \u001b[34m1\u001b[39;49;00m)]\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[90m@loader\u001b[39;49;00m(\u001b[33m'\u001b[39;49;00m\u001b[33mmy_datefile_loader\u001b[39;49;00m\u001b[33m'\u001b[39;49;00m)\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[34mdef\u001b[39;49;00m\u001b[37m \u001b[39;49;00m\u001b[32mload_datefile\u001b[39;49;00m(infile):\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[34mdef\u001b[39;49;00m\u001b[37m \u001b[39;49;00m\u001b[32mcreate_date\u001b[39;49;00m(row):\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[34mreturn\u001b[39;49;00m pd.Timestamp(row[\u001b[33m'\u001b[39;49;00m\u001b[33myear\u001b[39;49;00m\u001b[33m'\u001b[39;49;00m], row[\u001b[33m'\u001b[39;49;00m\u001b[33mmonth\u001b[39;49;00m\u001b[33m'\u001b[39;49;00m], row[\u001b[33m'\u001b[39;49;00m\u001b[33mday\u001b[39;49;00m\u001b[33m'\u001b[39;49;00m])\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " df = pd.read_csv(infile, index_col=\u001b[34m0\u001b[39;49;00m, sep=\u001b[33mr\u001b[39;49;00m\u001b[33m'\u001b[39;49;00m\u001b[33m\\\u001b[39;49;00m\u001b[33ms+\u001b[39;49;00m\u001b[33m'\u001b[39;49;00m)\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " df[\u001b[33m'\u001b[39;49;00m\u001b[33macquisition_date\u001b[39;49;00m\u001b[33m'\u001b[39;49;00m] = df.apply(create_date, axis=\u001b[34m1\u001b[39;49;00m)\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " df.drop([\u001b[33m'\u001b[39;49;00m\u001b[33myear\u001b[39;49;00m\u001b[33m'\u001b[39;49;00m, \u001b[33m'\u001b[39;49;00m\u001b[33mmonth\u001b[39;49;00m\u001b[33m'\u001b[39;49;00m, \u001b[33m'\u001b[39;49;00m\u001b[33mday\u001b[39;49;00m\u001b[33m'\u001b[39;49;00m], axis=\u001b[34m1\u001b[39;49;00m, inplace=\u001b[34mTrue\u001b[39;49;00m)\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[37m\u001b[39;49;00m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \u001b[34mreturn\u001b[39;49;00m df\u001b[37m\u001b[39;49;00m\n" ] } ], "source": [ "cat plugin_3.py | pygmentize" ] }, { "cell_type": "markdown", "id": "f169349b-64f6-4948-9eac-68daff1e772e", "metadata": {}, "source": [ "And to see it in action:" ] }, { "cell_type": "code", "execution_count": 66, "id": "b3324dfa-64d1-4ac0-91dc-5c01f30c1a98", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:25.741569Z", "iopub.status.busy": "2026-06-15T10:54:25.741485Z", "iopub.status.idle": "2026-06-15T10:54:26.207688Z", "shell.execute_reply": "2026-06-15T10:54:26.207235Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\tacquisition_date\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t2018-06-01T00:00:00\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t2018-06-17T00:00:00\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t2018-07-05T00:00:00\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t2018-03-11T00:00:00\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t2018-02-21T00:00:00\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t2018-08-08T00:00:00\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t2018-11-30T00:00:00\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t2018-12-05T00:00:00\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t2018-04-13T00:00:00\n" ] } ], "source": [ "fmrib_unpack -p plugin_3.py -l data_21.tsv my_datefile_loader out.tsv data_21.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "06e34a64-aac1-4a05-a397-f8ce5339dc4e", "metadata": {}, "source": [ "## Miscellaneous topics\n", "\n", "### Non-numeric data\n", "\n", "Many UK Biobank variables contain non-numeric data, such as alpha-numeric\n", "codes and unstructured text. If you want to select subjects on the basis of\n", "such columns, [data-field expressions](#Selecting-subjects-by-data-field-value)\n", "contain some simple mechanisms for doing so. Here is an example of a file\n", "containing both numeric and non-numeric data:" ] }, { "cell_type": "code", "execution_count": 67, "id": "1ad9a3de-a5b4-44d9-853d-c97fe2e54c66", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:26.208431Z", "iopub.status.busy": "2026-06-15T10:54:26.208350Z", "iopub.status.idle": "2026-06-15T10:54:26.319737Z", "shell.execute_reply": "2026-06-15T10:54:26.319283Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid 1-0.0 2-0.0 3-0.0 4-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1 A481 54 red green blue 0.6\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2 A590 24 yellow aqua 3.2\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3 B391 17 brown black purple 1.4\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4 D596 77 green 7.3\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5 Z980 26 white red 5.1\n" ] } ], "source": [ "cat data_22.tsv | column -t -s $'\\t'" ] }, { "cell_type": "markdown", "id": "8980200d-b73f-4590-8788-1cd82228a624", "metadata": {}, "source": [ "Let\u2019s say we are only interested in subjects where data-field 1 contains a\n", "value in the `A` category:\n", "\n", "> Note the use of the `-nb` (`--no_builtins`) option here - this tells\n", "> FUNPACK to ignore its built-in data-field table, which contains information\n", "> about the type of each UK Biobank data-field, and would otherwise interfere\n", "> with this example. You would almost never need to use this option normally." ] }, { "cell_type": "code", "execution_count": 68, "id": "8c8de2dd-76f9-4b45-867a-633d286c192f", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:26.320548Z", "iopub.status.busy": "2026-06-15T10:54:26.320474Z", "iopub.status.idle": "2026-06-15T10:54:26.751143Z", "shell.execute_reply": "2026-06-15T10:54:26.750620Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t2-0.0\t3-0.0\t4-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\tA481\t54\tred green blue\t0.6\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\tA590\t24\tyellow aqua\t3.2\n" ] } ], "source": [ "fmrib_unpack -nb -s \"v1 contains 'A'\" out.tsv data_22.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "79860e6d-03f7-4dbd-9f07-932b85323255", "metadata": {}, "source": [ "By default, FUNPACK will save columns containing non-numeric data to the\n", "main output file, just like any other column. However, there are a couple of\n", "options you can use to control what FUNPACK does with non-numeric data.\n", "\n", "If you only care about numeric columns, you can use the\n", "`--suppress_non_numerics` option (`-esn` for short) - this tells FUNPACK to\n", "discard all columns that are not numeric:" ] }, { "cell_type": "code", "execution_count": 69, "id": "7e5ccb77-4b27-41cd-8640-f2b6aa99adc9", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:26.752654Z", "iopub.status.busy": "2026-06-15T10:54:26.752500Z", "iopub.status.idle": "2026-06-15T10:54:27.210490Z", "shell.execute_reply": "2026-06-15T10:54:27.210056Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t2-0.0\t4-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t54\t0.6\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t24\t3.2\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t17\t1.4\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t77\t7.3\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t26\t5.1\n" ] } ], "source": [ "fmrib_unpack -nb -esn out.tsv data_22.tsv\n", "cat out.tsv" ] }, { "cell_type": "markdown", "id": "308a77aa-7030-4681-be49-c3141ae8c598", "metadata": {}, "source": [ "You can also tell FUNPACK to save all non-numeric columns to a separate file,\n", "using the `--write_non_numerics` option (`-wnn` for short):" ] }, { "cell_type": "code", "execution_count": 70, "id": "0967634a-7bfb-4ab3-9203-72e5ef7f3371", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:27.211274Z", "iopub.status.busy": "2026-06-15T10:54:27.211202Z", "iopub.status.idle": "2026-06-15T10:54:27.708775Z", "shell.execute_reply": "2026-06-15T10:54:27.708340Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eid\t2-0.0\t4-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t54\t0.6\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t24\t3.2\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t17\t1.4\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t77\t7.3\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t26\t5.1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "eid\t1-0.0\t3-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\tA481\tred green blue\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\tA590\tyellow aqua\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\tB391\tbrown black purple\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\tD596\tgreen\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\tZ980\twhite red\n" ] } ], "source": [ "fmrib_unpack -nb -esn -wnn out.tsv data_22.tsv\n", "cat out.tsv\n", "cat out_non_numerics.tsv" ] }, { "cell_type": "markdown", "id": "f6b12ccd-f249-4f09-beb6-b676b1c0fb71", "metadata": {}, "source": [ "### Dry run\n", "\n", "The `--dry_run` (`-d` for short) option allows you to see what FUNPACK is\n", "going to do - it is useful to perform a dry run before running a large\n", "processing job, which could take a long time. For example, if we have a\n", "complicated configuration such as the following, we can use the `--dry_run`\n", "option to check that FUNPACK is going to do what we expect:" ] }, { "cell_type": "code", "execution_count": 71, "id": "04752be6-3f43-4efa-9d25-7b2065544089", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:27.709520Z", "iopub.status.busy": "2026-06-15T10:54:27.709455Z", "iopub.status.idle": "2026-06-15T10:54:28.414084Z", "shell.execute_reply": "2026-06-15T10:54:28.413609Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "funpack 4.0.1.dev10+g2ea26548b dry run\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Input data\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Loaded columns: 11\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Ignored columns: 0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Unknown columns: 10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Uncategorised columns: 0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Loaded variables: 11\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Cleaning\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " NA Insertion: True\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 1: [7.0, 8.0, 9.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Cleaning functions: True\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 4: [makeNa[cleaner](< 50)]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Child value replacement: True\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 3: [v4 != 20] -> [25.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Categorical recoding: True\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 2: [1.0, 2.0, 3.0] -> [100.0, 200.0, 300.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Processing: True\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 1: ['all' list([])] -> [removeIfSparse[processor](minpres=0.5)]\n" ] } ], "source": [ "fmrib_unpack \\\n", " -nb -d \\\n", " -nv 1 \"7,8,9\" \\\n", " -re 2 \"1,2,3\" \"100,200,300\" \\\n", " -cv 3 \"v4 != 20\" \"25\" \\\n", " -cl 4 \"makeNa('< 50')\" \\\n", " -apr all \"removeIfSparse(minpres=0.5)\" \\\n", " out.tsv data_01.tsv" ] }, { "cell_type": "markdown", "id": "005d4b33-5097-44b3-8a8d-dcd9613cd4f6", "metadata": {}, "source": [ "### Built-in rules\n", "\n", "FUNPACK has a large number of hand-crafted rules built in, which are\n", "specific to UK Biobank data-fields. These rules are part of the `fmrib`\n", "configuration, which can be used by adding `-cfg fmrib` to the\n", "command-line options.\n", "\n", "We can use the `--dry_run` (`-d` for short) option, along with some dummy data\n", "files which just contain the UK Biobank column names, to get a summary of\n", "these rules:" ] }, { "cell_type": "code", "execution_count": 72, "id": "c01240c5-9298-43c1-bcd2-8ae3758a1651", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:28.415955Z", "iopub.status.busy": "2026-06-15T10:54:28.415895Z", "iopub.status.idle": "2026-06-15T10:54:43.980664Z", "shell.execute_reply": "2026-06-15T10:54:43.980300Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "funpack 4.0.1.dev10+g2ea26548b dry run\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Input data\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Loaded columns: 25198\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Ignored columns: 0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Unknown columns: 1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Uncategorised columns: 1403\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Loaded variables: 7240\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Cleaning\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " NA Insertion: True\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 19: [3.0, 6.0, 7.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 21: [-1.0, 4.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 23: [6.0, 7.0, 9.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 84: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 87: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 92: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 129: [-1.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 130: [-1.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 400: [0.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 670: [-3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 680: [-3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 699: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 709: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 728: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 738: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 757: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 767: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 777: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 796: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 806: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 816: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 826: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 845: [-1.0, -2.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 864: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 874: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 884: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 894: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 904: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 914: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 924: [-3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 943: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 971: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 981: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 991: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 1001: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 1011: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 1021: [-1.0, -3.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 1031: [-1.0, -3.0]\n", "\n...\n[Long output - 3677 more lines hidden]\n...\n" ] } ], "source": [ "fmrib_unpack -cfg fmrib -d out.tsv ukbcols.csv" ] }, { "cell_type": "markdown", "id": "62391ccc-7cfd-46a4-8389-b08445263a18", "metadata": {}, "source": [ "All of these rules are coded in a set of `.cfg` and `.tsv` files which are\n", "installed alongside the FUNPACK source code:" ] }, { "cell_type": "code", "execution_count": 73, "id": "6f896d51-3d5d-4b45-8c9a-03d77d3b7212", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:43.981425Z", "iopub.status.busy": "2026-06-15T10:54:43.981359Z", "iopub.status.idle": "2026-06-15T10:54:44.418256Z", "shell.execute_reply": "2026-06-15T10:54:44.417887Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "total 32\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "-rw-r--r-- 1 root root 236 Jun 15 11:53 README\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "drwxr-xr-x 2 root root 4096 Jun 15 11:53 fmrib\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "-rw-r--r-- 1 root root 2403 Jun 15 11:53 fmrib.cfg\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "-rw-r--r-- 1 root root 752 Jun 15 11:53 fmrib_cats.cfg\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "-rw-r--r-- 1 root root 607 Jun 15 11:53 fmrib_logs.cfg\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "-rw-r--r-- 1 root root 599 Jun 15 11:53 fmrib_new_release.cfg\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "-rw-r--r-- 1 root root 168 Jun 15 11:53 fmrib_standard.cfg\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "-rw-r--r-- 1 root root 411 Jun 15 11:53 local.cfg\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "total 44\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "-rw-r--r-- 1 root root 12410 Jun 15 11:53 categories.tsv\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "-rw-r--r-- 1 root root 3601 Jun 15 11:53 datacodings_navalues.tsv\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "-rw-r--r-- 1 root root 2595 Jun 15 11:53 datacodings_recoding.tsv\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "-rw-r--r-- 1 root root 61 Jun 15 11:53 datetime_formatting.tsv\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "-rw-r--r-- 1 root root 3396 Jun 15 11:53 processing.tsv\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "-rw-r--r-- 1 root root 60 Jun 15 11:53 variables_clean.tsv\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "-rw-r--r-- 1 root root 5703 Jun 15 11:53 variables_parentvalues.tsv\n" ] } ], "source": [ "cfgdir=$(python -c \"import funpack; print(funpack.findConfigDir())\")\n", "ls -l $cfgdir/\n", "ls -l $cfgdir/fmrib/" ] }, { "cell_type": "markdown", "id": "df4cf34c-ec8f-4be3-882b-ff2d4e4d45ea", "metadata": {}, "source": [ "The key files are:\n", "\n", "- `variables_*.tsv`: Child value replacement, and cleaning rules for each\n", " data-field.\n", "- `datacodings_*.tsv`: NA insertion and recoding rules for data-codings -\n", " these are used when rules are not explicitly specified in the\n", " `variables_*.tsv` files, for a variable which uses a given data-coding.\n", "- `processing.tsv`: List of all processing functions that are applied, in\n", " order.\n", "- `categories.tsv`: Data-field categories, for use with the `--category`/`-c`\n", " option.\n", "\n", "> Note that these rules are released as a separate package called\n", "> [fmrib-unpack-fmrib-config](https://git.fmrib.ox.ac.uk/fsl/funpack-fmrib-config/),\n", "> but are automatically installed when you install FUNPACK.\n", "\n", "If you are not happy with some of the rules defined in these files, you have the\n", "following options:\n", "\n", "1. Override them on the command-line, or in a configuration file (see below)\n", "\n", "2. Modify them in place.\n", "\n", "3. Create your own versions of the files, and pass them via the following\n", " command-line options:\n", "\n", " - `--variable_file` (`-vf` for short)\n", " - `--datacoding_file` (`-df` for short)\n", " - `--type_file` (`-tf` for short)\n", " - `--processing_file` (`-pf` for short)\n", " - `--category_file` (`-cf` for short)\n", "\n", "Rules which you provide on the command-line or via the `-vf` and `-df` options\n", "will override built-in rules for the same data-fields/data-codings.\n", "\n", "The data-field and data-coding rules can be stored across multiple files - for\n", "example, you may want to write all of the NA insertion rules in one file, and\n", "all of the child value replacement rules in another. FUNPACK will merge\n", "all of the built-in files and any additionally provided files together, so you\n", "do not need to maintain large and unwieldy data-field/data-coding tables.\n", "\n", "### Using a configuration file\n", "\n", "FUNPACK has an extensive command-line interface, but you don\u2019t need to pass\n", "all of the settings via the command-line. Instead, you can put them into a\n", "file, and give that file to FUNPACK with the `--config` (`-cfg` for short)\n", "option. You need to use the long-form of each command-line option, without the\n", "leading `--`.\n", "\n", "Let\u2019s take our example from the [dry run section](#Dry-run), and put all of\n", "the options into a configuration file:" ] }, { "cell_type": "code", "execution_count": 74, "id": "c326aa93-e1ac-4809-a1f2-88e37be4ef3e", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:44.418992Z", "iopub.status.busy": "2026-06-15T10:54:44.418927Z", "iopub.status.idle": "2026-06-15T10:54:45.178991Z", "shell.execute_reply": "2026-06-15T10:54:45.178620Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "no_builtins\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "quiet\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "overwrite\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "na_values 1 \"7,8,9\"\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "recoding 2 \"1,2,3\" \"100,200,300\"\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "child_values 3 \"v4 != 20\" \"25\"\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "clean 4 \"makeNa('< 50')\"\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "append_process all \"removeIfSparse(minpres=0.5)\"\n" ] } ], "source": [ "cat < config.txt\n", "no_builtins\n", "quiet\n", "overwrite\n", "na_values 1 \"7,8,9\"\n", "recoding 2 \"1,2,3\" \"100,200,300\"\n", "child_values 3 \"v4 != 20\" \"25\"\n", "clean 4 \"makeNa('< 50')\"\n", "append_process all \"removeIfSparse(minpres=0.5)\"\n", "EOF\n", "\n", "cat config.txt" ] }, { "cell_type": "markdown", "id": "3616eb7a-6db1-4936-a618-f9ede20bc304", "metadata": {}, "source": [ "Now we can pass this file to FUNPACK instead of having to pass all of the\n", "command line options:" ] }, { "cell_type": "code", "execution_count": 75, "id": "6058f9e2-5b41-4b02-9589-c139a3155943", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:45.179713Z", "iopub.status.busy": "2026-06-15T10:54:45.179650Z", "iopub.status.idle": "2026-06-15T10:54:45.555444Z", "shell.execute_reply": "2026-06-15T10:54:45.555099Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "funpack 4.0.1.dev10+g2ea26548b dry run\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Input data\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Loaded columns: 11\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Ignored columns: 0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Unknown columns: 10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Uncategorised columns: 0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Loaded variables: 11\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Cleaning\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " NA Insertion: True\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 1: [7.0, 8.0, 9.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Cleaning functions: True\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 4: [makeNa[cleaner](< 50)]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Child value replacement: True\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 3: [v4 != 20] -> [25.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Categorical recoding: True\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 2: [1.0, 2.0, 3.0] -> [100.0, 200.0, 300.0]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Processing: True\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 1: ['all' list([])] -> [removeIfSparse[processor](minpres=0.5)]\n" ] } ], "source": [ "fmrib_unpack -d -cfg config.txt out.tsv data_01.tsv" ] }, { "cell_type": "markdown", "id": "b81f4de8-b4c4-43db-a2ba-9fcbc13c1447", "metadata": {}, "source": [ "### Working with unknown/uncategorised variables\n", "\n", "Future UK Biobank data releases may contain new data-fields that are not\n", "present in the built-in data-field table used by FUNPACK, and thus are not\n", "recognised as UKB data-fields.\n", "\n", "Furthermore, if you are working with the hand-crafted data-field categories\n", "from the [built-in fmrib configuration](#Built-in-rules), or your own\n", "categories, a new data release may contain data-fields which are not included\n", "in any category.\n", "\n", "To help you identify these new data-fields, FUNPACK has the ability to inform\n", "you about data-fields that it does not know about, or that are not categorised.\n", "\n", "To demonstrate, let\u2019s create a dummy data-field table which lists all of the\n", "data-fields that we do know about - data-fields 1 to 5. We\u2019ll also create a\n", "custom category file, which adds data-fields 1 to 3 to a category:" ] }, { "cell_type": "code", "execution_count": 76, "id": "7be4d0a9-0757-433c-bf68-50d2c885f41e", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:45.556186Z", "iopub.status.busy": "2026-06-15T10:54:45.556121Z", "iopub.status.idle": "2026-06-15T10:54:45.898413Z", "shell.execute_reply": "2026-06-15T10:54:45.898098Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ID\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "ID\tCategory\tVariables\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\tmy category\t1:3\n" ] } ], "source": [ "echo -e \"ID\\n1\\n2\\n3\\n4\\n5\\n\" > custom_variables.tsv\n", "echo -e \"ID\\tCategory\\tVariables\" > custom_categories.tsv\n", "echo -e \"1\\tmy category\\t1:3\" >> custom_categories.tsv\n", "cat custom_variables.tsv\n", "cat custom_categories.tsv" ] }, { "cell_type": "markdown", "id": "f60a715b-22e8-44eb-b183-9c74e056b1f6", "metadata": {}, "source": [ "Now we can use the `--write_unknown_vars` option (`-wu` for short) to generate\n", "a summary of the data-fields which FUNPACK did not recognise, or which were\n", "not in any category:\n", "\n", "> Again we are using the `-nb` (`--no_builtins`) option, which tells FUNPACK\n", "> not to load its built-in table of UK Biobank variables." ] }, { "cell_type": "code", "execution_count": 77, "id": "e0d19d9d-f30c-4c82-900f-19033ad23a0f", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:45.899094Z", "iopub.status.busy": "2026-06-15T10:54:45.899036Z", "iopub.status.idle": "2026-06-15T10:54:46.318014Z", "shell.execute_reply": "2026-06-15T10:54:46.317622Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "name\tfile\tclass\texported\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6-0.0\t{{ dir_prefix }}/data_01.tsv\tunknown\t1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7-0.0\t{{ dir_prefix }}/data_01.tsv\tunknown\t1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8-0.0\t{{ dir_prefix }}/data_01.tsv\tunknown\t1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9-0.0\t{{ dir_prefix }}/data_01.tsv\tunknown\t1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10-0.0\t{{ dir_prefix }}/data_01.tsv\tunknown\t1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4-0.0\t{{ dir_prefix }}/data_01.tsv\tuncategorised\t1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5-0.0\t{{ dir_prefix }}/data_01.tsv\tuncategorised\t1\n" ] } ], "source": [ "fmrib_unpack -nb -vf custom_variables.tsv -cf custom_categories.tsv -wu out.tsv data_01.tsv\n", "cat out_unknown_vars.txt" ] }, { "cell_type": "markdown", "id": "5ed0f7d1-81da-4606-a268-43ada6f8d555", "metadata": {}, "source": [ "This file contains a summary of the columns that were uncategorised or not\n", "recognised, and whether they were exported to the output file. If an\n", "unknown/uncategorised data-field was not exported (e.g.\u00a0it was removed during\n", "[processing](#Processing-examples) by a sparsity or redundancy check), the\n", "`exported` column will contain a `0` for that data-field.\n", "\n", "If you are specifically interested in querying or working with these\n", "unknown/uncategorised data-fields, you can select them with the\n", "automatically-generated `unknown`/`uncategorised` categories:" ] }, { "cell_type": "code", "execution_count": 78, "id": "75a6642c-23b5-4bbd-9789-a1934dad59bb", "metadata": { "execution": { "iopub.execute_input": "2026-06-15T10:54:46.318847Z", "iopub.status.busy": "2026-06-15T10:54:46.318783Z", "iopub.status.idle": "2026-06-15T10:54:47.230483Z", "shell.execute_reply": "2026-06-15T10:54:47.230105Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Unknown data-fields:\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "eid\t6-0.0\t7-0.0\t8-0.0\t9-0.0\t10-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t22\t56\t65\t90\t12\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t35\t3\t65\t50\t67\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t36\t96\t62\t48\t59\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t20\t18\t72\t37\t27\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t84\t11\t28\t69\t10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t46\t14\t60\t73\t80\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t23\t39\t68\t7\t63\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t83\t98\t36\t6\t23\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t12\t95\t73\t2\t62\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t20\t97\t57\t59\t23\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Uncategorised data-fields:\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "eid\t4-0.0\t5-0.0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1\t11\t84\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2\t42\t89\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "3\t84\t93\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "4\t48\t80\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "5\t68\t80\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "6\t59\t7\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7\t46\t92\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "8\t30\t92\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "9\t79\t16\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "10\t41\t8\n" ] } ], "source": [ "fmrib_unpack -nb -vf custom_variables.tsv -cf custom_categories.tsv -c unknown unknowns.tsv data_01.tsv\n", "fmrib_unpack -nb -vf custom_variables.tsv -cf custom_categories.tsv -c uncategorised uncategorised.tsv data_01.tsv\n", "echo \"Unknown data-fields:\"\n", "cat unknowns.tsv\n", "echo \"Uncategorised data-fields:\"\n", "cat uncategorised.tsv" ] } ], "metadata": { "kernelspec": { "display_name": "Bash", "language": "bash", "name": "bash" }, "language_info": { "codemirror_mode": "shell", "file_extension": ".sh", "mimetype": "text/x-sh", "name": "bash" } }, "nbformat": 4, "nbformat_minor": 5 }