genal-python 0.4__tar.gz → 0.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. {genal_python-0.4 → genal_python-0.6}/.gitignore +2 -1
  2. {genal_python-0.4 → genal_python-0.6}/PKG-INFO +98 -81
  3. {genal_python-0.4 → genal_python-0.6}/README.md +97 -80
  4. genal_python-0.6/docs/_build/doctrees/api.doctree +0 -0
  5. genal_python-0.6/docs/_build/doctrees/environment.pickle +0 -0
  6. genal_python-0.6/docs/_build/doctrees/genal.doctree +0 -0
  7. genal_python-0.6/docs/_build/doctrees/index.doctree +0 -0
  8. genal_python-0.6/docs/_build/doctrees/introduction.doctree +0 -0
  9. genal_python-0.6/docs/_build/doctrees/modules.doctree +0 -0
  10. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/.buildinfo +1 -1
  11. genal_python-0.6/docs/_build/html/_sources/index.rst.txt +59 -0
  12. genal_python-0.6/docs/_build/html/api.html +876 -0
  13. genal_python-0.6/docs/_build/html/genal.html +2039 -0
  14. genal_python-0.6/docs/_build/html/genindex.html +701 -0
  15. genal_python-0.6/docs/_build/html/index.html +192 -0
  16. genal_python-0.6/docs/_build/html/introduction.html +584 -0
  17. genal_python-0.6/docs/_build/html/modules.html +269 -0
  18. genal_python-0.6/docs/_build/html/objects.inv +0 -0
  19. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/py-modindex.html +21 -14
  20. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/search.html +9 -2
  21. genal_python-0.6/docs/_build/html/searchindex.js +1 -0
  22. genal_python-0.6/docs/source/api.rst +24 -0
  23. genal_python-0.6/docs/source/genal.rst +101 -0
  24. {genal_python-0.4 → genal_python-0.6}/docs/source/index.rst +1 -1
  25. genal_python-0.6/docs/source/introduction.rst +505 -0
  26. genal_python-0.6/docs/source/modules.rst +7 -0
  27. {genal_python-0.4 → genal_python-0.6}/genal/Geno.py +112 -115
  28. {genal_python-0.4 → genal_python-0.6}/genal/MR.py +207 -43
  29. {genal_python-0.4 → genal_python-0.6}/genal/MR_tools.py +10 -18
  30. {genal_python-0.4 → genal_python-0.6}/genal/MRpresso.py +1 -1
  31. {genal_python-0.4 → genal_python-0.6}/genal/__init__.py +2 -2
  32. {genal_python-0.4 → genal_python-0.6}/genal/association.py +3 -0
  33. {genal_python-0.4 → genal_python-0.6}/genal/constants.py +7 -5
  34. {genal_python-0.4 → genal_python-0.6}/genal/geno_tools.py +19 -11
  35. {genal_python-0.4 → genal_python-0.6}/genal/lift.py +1 -1
  36. {genal_python-0.4 → genal_python-0.6}/genal/tools.py +2 -2
  37. {genal_python-0.4 → genal_python-0.6}/pyproject.toml +1 -1
  38. genal_python-0.4/docs/_build/doctrees/environment.pickle +0 -0
  39. genal_python-0.4/docs/_build/doctrees/index.doctree +0 -0
  40. genal_python-0.4/docs/_build/html/_sources/index.rst.txt +0 -20
  41. genal_python-0.4/docs/_build/html/genindex.html +0 -562
  42. genal_python-0.4/docs/_build/html/index.html +0 -113
  43. genal_python-0.4/docs/_build/html/objects.inv +0 -0
  44. genal_python-0.4/docs/_build/html/searchindex.js +0 -1
  45. {genal_python-0.4 → genal_python-0.6}/LICENSE +0 -0
  46. {genal_python-0.4 → genal_python-0.6}/docs/Images/MR_plot_SBP_AS.png +0 -0
  47. {genal_python-0.4 → genal_python-0.6}/docs/Makefile +0 -0
  48. {genal_python-0.4 → genal_python-0.6}/docs/_build/doctrees/source/genal.doctree +0 -0
  49. {genal_python-0.4 → genal_python-0.6}/docs/_build/doctrees/source/modules.doctree +0 -0
  50. /genal_python-0.4/docs/source/api.rst → /genal_python-0.6/docs/_build/html/_sources/api.rst.txt +0 -0
  51. /genal_python-0.4/docs/source/genal.rst → /genal_python-0.6/docs/_build/html/_sources/genal.rst.txt +0 -0
  52. /genal_python-0.4/docs/source/introduction.rst → /genal_python-0.6/docs/_build/html/_sources/introduction.rst.txt +0 -0
  53. {genal_python-0.4/docs/_build/html/_sources/source → genal_python-0.6/docs/_build/html/_sources}/modules.rst.txt +0 -0
  54. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_sources/source/genal.rst.txt +0 -0
  55. /genal_python-0.4/docs/source/modules.rst → /genal_python-0.6/docs/_build/html/_sources/source/modules.rst.txt +0 -0
  56. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/_sphinx_javascript_frameworks_compat.js +0 -0
  57. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/basic.css +0 -0
  58. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/css/badge_only.css +0 -0
  59. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff +0 -0
  60. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff2 +0 -0
  61. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff +0 -0
  62. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff2 +0 -0
  63. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/css/fonts/fontawesome-webfont.eot +0 -0
  64. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/css/fonts/fontawesome-webfont.svg +0 -0
  65. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/css/fonts/fontawesome-webfont.ttf +0 -0
  66. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff +0 -0
  67. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff2 +0 -0
  68. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/css/fonts/lato-bold-italic.woff +0 -0
  69. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/css/fonts/lato-bold-italic.woff2 +0 -0
  70. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/css/fonts/lato-bold.woff +0 -0
  71. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/css/fonts/lato-bold.woff2 +0 -0
  72. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/css/fonts/lato-normal-italic.woff +0 -0
  73. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/css/fonts/lato-normal-italic.woff2 +0 -0
  74. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/css/fonts/lato-normal.woff +0 -0
  75. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/css/fonts/lato-normal.woff2 +0 -0
  76. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/css/theme.css +0 -0
  77. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/doctools.js +0 -0
  78. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/documentation_options.js +0 -0
  79. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/file.png +0 -0
  80. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/jquery.js +0 -0
  81. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/js/badge_only.js +0 -0
  82. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/js/html5shiv-printshiv.min.js +0 -0
  83. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/js/html5shiv.min.js +0 -0
  84. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/js/theme.js +0 -0
  85. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/language_data.js +0 -0
  86. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/minus.png +0 -0
  87. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/plus.png +0 -0
  88. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/pygments.css +0 -0
  89. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/searchtools.js +0 -0
  90. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/_static/sphinx_highlight.js +0 -0
  91. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/source/genal.html +0 -0
  92. {genal_python-0.4 → genal_python-0.6}/docs/_build/html/source/modules.html +0 -0
  93. {genal_python-0.4 → genal_python-0.6}/docs/make.bat +0 -0
  94. {genal_python-0.4 → genal_python-0.6}/docs/requirements.txt +0 -0
  95. {genal_python-0.4 → genal_python-0.6}/docs/source/conf.py +0 -0
  96. {genal_python-0.4 → genal_python-0.6}/genal/clump.py +0 -0
  97. {genal_python-0.4 → genal_python-0.6}/genal/extract_prs.py +0 -0
  98. {genal_python-0.4 → genal_python-0.6}/genal/proxy.py +0 -0
  99. {genal_python-0.4 → genal_python-0.6}/gitignore +0 -0
  100. {genal_python-0.4 → genal_python-0.6}/readthedocs.yaml +0 -0
  101. {genal_python-0.4 → genal_python-0.6}/requirements.txt +0 -0
@@ -2,4 +2,5 @@ __pycache__/
2
2
  dist/
3
3
  .ipynb_checkpoints/
4
4
  ipynb_checkpoints/
5
- genal/.ipynb_checkpoints/
5
+ genal/.ipynb_checkpoints/
6
+ docs/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: genal-python
3
- Version: 0.4
3
+ Version: 0.6
4
4
  Summary: A python toolkit for polygenic risk scoring and mendelian randomization.
5
5
  Author-email: Cyprien Rivier <riviercyprien@gmail.com>
6
6
  Requires-Python: >=3.7
@@ -26,12 +26,14 @@ Project-URL: Home, https://github.com/CypRiv/genal
26
26
 
27
27
  **This project was developed by Cyprien A. Rivier**
28
28
 
29
+
29
30
  # Table of contents
30
31
  1. [Introduction](#introduction)
31
- 2. [Requirements for the genal module](#paragraph1)
32
- 3. [Installation and how to use genal](#paragraph2)
32
+ 2. [Citation] (#citation)
33
+ 3. [Requirements for the genal module](#paragraph1)
34
+ 4. [Installation and how to use genal](#paragraph2)
33
35
  1. [Installation](#paragraph2.1)
34
- 4. [Tutorial and presentation of the main tools](#paragraph3)
36
+ 5. [Tutorial and presentation of the main tools](#paragraph3)
35
37
  1. [Data loading](#paragraph3.1)
36
38
  2. [Data preprocessing](#paragraph3.2)
37
39
  3. [Clumping](#paragraph3.3)
@@ -41,8 +43,6 @@ Project-URL: Home, https://github.com/CypRiv/genal
41
43
  7. [Lifting](#paragraph3.7)
42
44
 
43
45
 
44
-
45
-
46
46
  ## Introduction <a name="introduction"></a>
47
47
  Genal is a python module designed to make it easy to run genetic risk scores and mendelian randomization analyses. It integrates a collection of tools that facilitate the cleaning of single nucleotide polymorphism data (usually derived from Genome-Wide Association Studies) and enable the execution of clinical population genetic workflows. The functionalities provided by genal include clumping, lifting, association testing, polygenic risk scoring, and Mendelian randomization analyses, all within a single Python module.
48
48
 
@@ -50,6 +50,10 @@ The module prioritizes user-friendliness and intuitive operation, aiming to redu
50
50
 
51
51
  Genal draws on concepts from well-established R packages such as TwoSampleMR, MR-Presso, MendelianRandomization, and gwasvcf, adapting their proven methodologies to the Python environment. This approach ensures that users have access to tried and tested techniques with the versatility of Python's data science tools.
52
52
 
53
+ ## Citation <a name="citation"></a>
54
+ If you're using genal, please cite the following paper:
55
+ **Genal: A Python Toolkit for Genetic Risk Scoring and Mendelian Randomization.** Cyprien A. Rivier, Santiago Clocchiatti-Tuozzo, Shufan Huo, Victor Torres-Lopez, Daniela Renedo, Kevin N. Sheth, Guido J. Falcone, Julian N. Acosta. medRxiv 2024.05.23.24307776; doi: https://doi.org/10.1101/2024.05.23.24307776
56
+
53
57
  ## Requirements for the genal module <a name="paragraph1"></a>
54
58
  ***Python 3.9 or later***. https://www.python.org/ <br>
55
59
 
@@ -75,7 +79,7 @@ genal.set_plink(path="/path/to/plink/executable/file")
75
79
  ```
76
80
 
77
81
  ## Tutorial <a name="paragraph3"></a>
78
- For this tutorial, we will build a Polygenic Risk Score (PRS) for systolic blood pressure (SBP) and investigate its genetically-determined effect on the risk of stroke. We will utilize summary statistics from Genome-Wide Association Studies (GWAS) and individual-level data from the UK Biobank. The steps include:
82
+ For this tutorial, we will obtain genetic instruments for systolic blood pressure (SBP), compute a Polygenic Risk Score (PRS), and run a Mendelian Randomization analysis to investigate the genetically-determined effect of SBP on the risk of stroke. We will utilize summary statistics from Genome-Wide Association Studies (GWAS) and individual-level data from the UK Biobank. The steps include:
79
83
 
80
84
  - Data loading
81
85
  - Data preprocessing
@@ -84,7 +88,7 @@ For this tutorial, we will build a Polygenic Risk Score (PRS) for systolic blood
84
88
  - Build a genomic risk score for SBP in a test population
85
89
  - Include risk score calculations with proxies
86
90
  - Perform Mendelian Randomization
87
- - Analyze SBP as an exposure and acute ischemic stroke as an outcome
91
+ - Analyze SBP as an exposure and acute stroke as an outcome
88
92
  - Plot the results
89
93
  - Conduct sensitivity analyses using the weighted median, MR-Egger, and MR-PRESSO methods
90
94
  - Calibrate SNP-trait weights with individual-level genetic data
@@ -116,17 +120,17 @@ sbp_gwas.head(5)
116
120
  We can now load this data into a `genal.Geno` instance. The `genal.Geno` class is the central piece of the package. It is designed to store Single Nucleotide Polymorphisms (SNP) data and make it easy to preprocess and clean.
117
121
 
118
122
  The `genal.Geno` takes as input a pandas dataframe where each row corresponds to a SNP, with columns describing the position and possibly the effect of the SNP for the given trait (SBP in our case). To indicate the names of the columns, the following arguments can be passed:
119
- - **CHR**: Column name for chromosome. Defaults to "CHR".
120
- - **POS**: Column name for genomic position. Defaults to "POS".
121
- - **SNP**: Column name for SNP identifier (rsid). Defaults to "SNP".
122
- - **EA**: Column name for effect allele. Defaults to "EA".
123
- - **NEA**: Column name for non-effect allele. Defaults to "NEA".
124
- - **BETA**: Column name for effect estimate. Defaults to "BETA".
125
- - **SE**: Column name for effect standard error. Defaults to "SE".
126
- - **P**: Column name for effect p-value. Defaults to "P".
127
- - **EAF**: Column name for effect allele frequency. Defaults to "EAF".
128
-
129
- After inspecting the dataframe, we first need to extract the chromosome and position information from the "MarkerName" column into two new columns "CHR" and "POS":
123
+ - **CHR**: Column name for chromosome. Defaults to `'CHR'`.
124
+ - **POS**: Column name for genomic position. Defaults to `'POS'`.
125
+ - **SNP**: Column name for SNP identifier (rsid). Defaults to `'SNP'`.
126
+ - **EA**: Column name for effect allele. Defaults to `'EA'`.
127
+ - **NEA**: Column name for non-effect allele. Defaults to `'NEA'`.
128
+ - **BETA**: Column name for effect estimate. Defaults to `'BETA'`.
129
+ - **SE**: Column name for effect standard error. Defaults to `'SE'`.
130
+ - **P**: Column name for effect p-value. Defaults to `'P'`.
131
+ - **EAF**: Column name for effect allele frequency. Defaults to `'EAF'`.
132
+
133
+ After inspecting the dataframe, we first need to extract the chromosome and position information from the `MarkerName` column into two new columns `CHR` and `POS`:
130
134
 
131
135
  ```python
132
136
  sbp_gwas[["CHR", "POS", "Filler"]] = sbp_gwas["MarkerName"].str.split(":", expand=True)
@@ -147,7 +151,7 @@ import genal
147
151
  SBP_Geno = genal.Geno(sbp_gwas, CHR="CHR", POS="POS", EA="Allele1", NEA="Allele2", BETA="Effect", SE="StdErr", P="P", EAF="Freq1", keep_columns=False)
148
152
  ```
149
153
 
150
- The last argument (`keep_columns = False`) indicates that we do not wish to keep the other (non-main) columns in the dataframe.
154
+ The last argument (`keep_columns = False`) indicates that we do not wish to keep the other (non-main) columns in the dataframe. Defaults to `True`.
151
155
 
152
156
  > **Note:**
153
157
  >
@@ -167,22 +171,23 @@ The `preprocessing` argument specifies the global level of preprocessing applied
167
171
  - `preprocessing = 'None'`: The data won't be modified.
168
172
  - `preprocessing = 'Fill'`: Missing columns will be added based on reference data and invalid values set to NaN, but no rows will be deleted.
169
173
  - `preprocessing = 'Fill_delete'`: Missing columns will be added, and all rows containing missing, duplicated, or invalid values will be deleted. This option is recommended before running genetic methods.
174
+ Defaults to `'Fill'`.
170
175
 
171
- By default, and depending on the global preprocessing level ('None', 'Fill', 'Fill_delete') chosen, the `preprocess_data` method of `genal.Geno` will run the following checks:
172
- - Ensure the CHR (chromosome) and POS (genomic position) columns are integers.
173
- - Ensure the EA (effect allele) and NEA (non-effect allele) columns are uppercase characters containing A, T, C, G letters. Multiallelic values are set to NaN.
174
- - Validate the P (p-value) column for proper values.
176
+ By default, and depending on the global preprocessing level (`'None'`, `'Fill'`, `'Fill_delete'`) chosen, the `preprocess_data` method of `genal.Geno` will run the following checks:
177
+ - Ensure the `CHR` (chromosome) and `POS` (genomic position) columns are integers.
178
+ - Ensure the `EA` (effect allele) and `NEA` (non-effect allele) columns are uppercase characters containing A, T, C, G letters. Multiallelic values are set to NaN.
179
+ - Validate the `P` (p-value) column for proper values.
175
180
  - Check for no duplicated SNPs based on rsid.
176
- - Determine if the BETA (effect) column contains beta estimates or odds ratios, and log-transform odds ratios if necessary.
177
- - Create SNP column using a reference panel if CHR and POS columns are present.
178
- - Create CHR and/or POS column using a reference panel if SNP column is present.
179
- - Create NEA (non-effect allele) column using a reference panel if EA (effect allele) column is present.
180
- - Create the SE (standard-error) column if the BETA and P (p-value) columns are present.
181
- - Create the P column if the BETA and SE columns are present.
181
+ - Determine if the `BETA` (effect) column contains beta estimates or odds ratios, and log-transform odds ratios if necessary.
182
+ - Create `SNP` column using a reference panel if CHR and POS columns are present.
183
+ - Create `CHR` and/or `POS` column using a reference panel if `SNP` column is present.
184
+ - Create `NEA` (non-effect allele) column using a reference panel if `EA` (effect allele) column is present.
185
+ - Create the `SE` (standard-error) column if the `BETA` and `P` (p-value) columns are present.
186
+ - Create the `P` column if the `BETA` and `SE` columns are present.
182
187
 
183
188
  If you do not wish to run certain steps, or wish to run only certain steps, you can use additional arguments. For more information, please refer to the `genal.Geno.preprocess_data` method in the API documentation.
184
189
 
185
- In our case, the SNP column (for SNP identifier - rsid) was missing from our dataframe and has been added based on a 1000 genome reference panel:
190
+ In our case, the `SNP` column (for SNP identifier - rsid) was missing from our dataframe and has been added based on a 1000 genome reference panel:
186
191
 
187
192
  Using the EUR reference panel.
188
193
  The SNP column (rsID) has been created. 197511(2.787%) SNPs were not found in the reference data and their ID set to CHR:POS:EA.
@@ -203,7 +208,7 @@ SBP_Geno.data
203
208
  | ... | .. | .. | ... | ... | ... | ... | ... | ... | ... |
204
209
  | 7088120 | A | G | 0.9028| -0.0184| 0.0517 | 0.722300 | 9 | 99999468 | rs10981301 |
205
210
 
206
- And we see that the SNP column with the rsids has been added based on the reference data.
211
+ And we see that the `SNP` column with the rsids has been added based on the reference data.
207
212
  You do not need to obtain the 1000 genome reference panel yourself, genal will download it the first time you use it. By default, the reference panel used is the european (eur) one. You can specify another valid reference panel (afr, eas, sas, amr) with the reference_panel argument:
208
213
 
209
214
  ```python
@@ -214,7 +219,7 @@ You can also use a custom reference panel by specifying to the reference_panel a
214
219
 
215
220
  ### Clumping <a name="paragraph3.3"></a>
216
221
 
217
- Clumping is the step at which we select the SNPs that will be used as our genetic instruments in future Polygenic Risk Scores and Mendelian Randomization analyses. The process involves identifying the SNPs that are strongly associated with our trait of interest (systolic blood pressure in this tutorial) and are independent from each other. This second step ensures that selected SNPs are not highly correlated, (i.e., they are not in close linkage disequilibrium). For this step, we again need to use a reference panel.
222
+ Clumping is the step at which we select the SNPs that will be used as our genetic instruments in future Polygenic Risk Scores and Mendelian Randomization analyses. The process involves identifying the SNPs that are strongly associated with our trait of interest (systolic blood pressure in this tutorial) and are independent from each other. This second step ensures that selected SNPs are not highly correlated, (i.e., they are not in high linkage disequilibrium). For this step, we again need to use a reference panel.
218
223
 
219
224
  The SNP-data loaded in a `genal.Geno` instance can be clumped using the `genal.Geno.clump` method. It will return another `genal.Geno` instance containing only the clumped data:
220
225
 
@@ -230,10 +235,10 @@ It will output the number of instruments obtained::
230
235
  1545 clumps formed from 73594 top variants.
231
236
 
232
237
  You can specify the thresholds you want to use for the clumping with the following arguments:
233
- - **p1**: P-value threshold during clumping. SNPs with a P-value higher than this value are excluded.
234
- - **r2**: Linkage disequilibrium threshold for the independence check. Takes values between 0 and 1.
235
- - **kb**: Genomic window used for the independence check (the unit is thousands of base-pair positions).
236
- - **reference_panel**: The reference population used to derive linkage disequilibrium values and select independent SNPs.
238
+ - `p1`: P-value threshold during clumping. SNPs with a P-value higher than this value are excluded. Defaults to `5e-8`.
239
+ - `r2`: Linkage disequilibrium threshold for the independence check. Takes values between 0 and 1. Defaults to `0.1`.
240
+ - `kb`: Genomic window used for the independence check (the unit is thousands of base-pair positions). Defaults to `250`.
241
+ - `reference_panel`: The reference population used to derive linkage disequilibrium values and select independent SNPs. Defaults to `eur`.
237
242
 
238
243
  ### Polygenic Risk Scoring <a name="paragraph3.4"></a>
239
244
 
@@ -243,7 +248,7 @@ Computing a Polygenic Risk Score (PRS) can be done in one line with the `genal.G
243
248
  SBP_clumped.prs(name = "SBP_prs", path = "path/to/genetic/files")
244
249
  ```
245
250
 
246
- The genetic files of the target population can be either one triple of bed/bim/fam files containing information for all SNPs, or they can be divided by chromosome (one bed/bim/fam triple for chr 1, another for chr 2, etc...). In the latter case, provide the path by replacing the chromosome number by '$' and genal will extract the necessary SNPs from each chromosome and merge them before running the PRS. For instance, if the genetic files are named `Pop_chr1.bed`, `Pop_chr1.bim`, `Pop_chr1.fam`, `Pop_chr2.bed`, ..., you can use:
251
+ The genetic files of the target population can be either contained in one triple of bed/bim/fam files with information for all SNPs, or divided by chromosome (one bed/bim/fam triple for chr 1, another for chr 2, etc...). In the latter case, provide the path by replacing the chromosome number by `$` and genal will extract the necessary SNPs from each chromosome and merge them before running the PRS. For instance, if the genetic files are named `Pop_chr1.bed`, `Pop_chr1.bim`, `Pop_chr1.fam`, `Pop_chr2.bed`, ..., you can use:
247
252
 
248
253
  ```python
249
254
  SBP_clumped.prs(name = "SBP_prs", path = "Pop_chr$")
@@ -283,7 +288,7 @@ The output of the `genal.Geno.prs` method will include how many SNPs were used t
283
288
  The PRS computation was successful and used 759/1545 (49.126%) SNPs.
284
289
  PRS data saved to SBP_prs.csv
285
290
 
286
- Here, we see that about half of the SNPs were not extracted from the data. In such cases, we may want to try and salvage some of these SNPs by looking for proxies (SNPs in high linkage disequilibrium, i.e. highly correlated SNPs). This can be done by specifying the 'proxy = True' argument:
291
+ Here, we see that about half of the SNPs were not extracted from the data. In such cases, we may want to try and salvage some of these SNPs by looking for proxies (SNPs in high linkage disequilibrium, i.e. highly correlated SNPs). This can be done by specifying the `proxy = True`. argument:
287
292
 
288
293
  ```python
289
294
  SBP_clumped.prs(name = "SBP_prs" ,path = "Pop_chr$", proxy = True, reference_panel = "eur", r2=0.8, kb=5000, window_snps=5000)
@@ -332,10 +337,10 @@ and the output is:
332
337
  In our case, we have been able to find proxies for 571 of the 786 SNPs that were missing in the population genetic data (7 potential proxies have been removed because they were identical to SNPs already present in our data).
333
338
 
334
339
  You can customize how the proxies are chosen with the following arguments:
335
- - **reference_panel**: The reference population used to derive linkage disequilibrium values and find proxies.
336
- - **kb**: Width of the genomic window to look for proxies (in thousands of base-pair positions).
337
- - **r2**: Minimum linkage disequilibrium value with the original SNP for a proxy to be included.
338
- - **window_snps**: Width of the window to look for proxies (in number of SNPs).
340
+ - `reference_panel`: The reference population used to derive linkage disequilibrium values and find proxies. Defaults to `eur`.
341
+ - `kb`: Width of the genomic window to look for proxies (in thousands of base-pair positions). Defaults to `5000`.
342
+ - `r2`: Minimum linkage disequilibrium value with the original SNP for a proxy to be included. Defaults to `0.8`.
343
+ - `window_snps`: Width of the window to look for proxies (in number of SNPs). Defaults to `5000`.
339
344
 
340
345
  > **Note:**
341
346
  >
@@ -344,7 +349,7 @@ You can customize how the proxies are chosen with the following arguments:
344
349
 
345
350
  ### Mendelian Randomization <a name="paragraph3.5"></a>
346
351
 
347
- To run MR, we need to load both our exposure and outcome SNP-level data in `genal.Geno` instances. In our case, the genetic instruments of the MR are the SNPs associated with blood pressure at genome-wide significant levels resulting from the clumping of the blood pressure GWAS. They are stored in our `SBP_clumped` `genal.Geno` instance which also include their association with the exposure trait (instrument-SBP estimates in the BETA column).
352
+ To run MR, we need to load both our exposure and outcome SNP-level data in `genal.Geno` instances. In our case, the genetic instruments of the MR are the SNPs associated with blood pressure at genome-wide significant levels resulting from the clumping of the blood pressure GWAS. They are stored in our `SBP_clumped` `genal.Geno` instance which also include their association with the exposure trait (instrument-SBP estimates in the `BETA` column).
348
353
 
349
354
  To get their association with the outcome trait (instrument-stroke estimates), we are going to use SNP-level data from a large GWAS of stroke performed by the GIGASTROKE consortium ([https://www.nature.com/articles/s41586-022-05165-3](https://www.nature.com/articles/s41586-022-05165-3)):
350
355
 
@@ -374,7 +379,7 @@ We preprocess it as well to put it in the correct format and make sure there is
374
379
  Stroke_Geno.preprocess_data(preprocessing = 'Fill_delete')
375
380
  ```
376
381
 
377
- Now, we need to extract our instruments (SNPs of the SBP_clumped data) from the outcome data to obtain their association with the outcome trait (stroke). It can be done by calling the `genal.Geno.query_outcome` method:
382
+ Now, we need to extract our instruments (SNPs of the `SBP_clumped` data) from the outcome data to obtain their association with the outcome trait (stroke). It can be done by calling the `genal.Geno.query_outcome` method:
378
383
 
379
384
  ```python
380
385
  SBP_clumped.query_outcome(Stroke_Geno, proxy = False)
@@ -403,67 +408,78 @@ And genal will print the number of missing instruments which have been proxied:
403
408
  Found proxies for 4 SNPs.
404
409
  (Exposure data, Outcome data, Outcome name) stored in the .MR_data attribute.
405
410
 
406
- After extracting the instruments from the outcome data, the SBP_clumped `genal.Geno` instance contains an 'MR_data' attribute containing the instruments-exposure and instruments-outcome associations necessary to run MR. Running MR is now as simple as calling the `genal.Geno.MR` method of the SBP_clumped `genal.Geno` instance:
411
+ After extracting the instruments from the outcome data, the `SBP_clumped` `genal.Geno` instance contains an `MR_data` attribute containing the instruments-exposure and instruments-outcome associations necessary to run MR. Running MR is now as simple as calling the `genal.Geno.MR` method of the SBP_clumped `genal.Geno` instance:
407
412
 
408
413
  ```python
409
- SBP_clumped.MR(action = 3, exposure_name = "SBP", outcome_name = "Stroke_eur")
414
+ SBP_clumped.MR(action = 2, exposure_name = "SBP", outcome_name = "Stroke_eur")
410
415
  ```
411
416
 
412
- The `genal.Geno.MR` method returns a dataframe containing the estimates and p-values for different MR methods:
413
- | exposure | outcome | method | nSNP | b | se | pval |
414
- |----------|-------------|-----------------------------------------|------|----------|----------|---------------|
415
- | SBP | Stroke_eur | Inverse-Variance Weighted | 1314 | 0.023376 | 0.001131 | 7.238794e-95 |
416
- | SBP | Stroke_eur | Inverse Variance Weighted (Fixed Effects)| 1314 | 0.023376 | 0.000806 | 8.391230e-185 |
417
- | SBP | Stroke_eur | Unweighted Regression | 1314 | 0.021736 | 0.078596 | 7.821255e-01 |
418
- | SBP | Stroke_eur | Weighted Median | 1314 | 0.022872 | 0.001437 | 4.984142e-57 |
419
- | SBP | Stroke_eur | Penalised Weighted Median | 1314 | 0.021472 | 0.001418 | 8.950351e-52 |
420
- | SBP | Stroke_eur | Simple Median | 1314 | 0.021447 | 0.001374 | 6.521750e-55 |
421
- | SBP | Stroke_eur | Sign concordance test | 1312 | 0.373476 | NaN | 1.664938e-42 |
422
- | SBP | Stroke_eur | MR Egger | 1314 | 0.029292 | 0.003060 | 5.009624e-21 |
423
- | SBP | Stroke_eur | Egger Intercept | 1314 | -0.001798| 0.000864 | 3.768249e-02 |
424
- | SBP | Stroke_eur | MR Egger bootstrap | 1314 | 0.030269 | 0.002076 | 0.000000e+00 |
425
- | SBP | Stroke_eur | Egger Intercept bootstrap | 1314 | -0.002794| 0.000699 | 0.000000e+00 |
417
+ The `genal.Geno.MR` method prints a message specifying which SNPs have been excluded from the analysis (it depends on the action argument, as we will see):
426
418
 
419
+ Action = 2: 42 SNPs excluded for being palindromic with intermediate allele frequencies: rs11817866, rs3802517, rs2788293, rs2274224, rs7310615, rs7953257, rs2024385, rs61912333, rs11632436, rs1012089, rs3851018, rs9899540, rs4617956, rs773432, rs11585169, rs7796, rs2487904, rs12321, rs73029563, rs4673238, rs3845811, rs2160236, rs10165271, rs9848170, rs2724535, rs6842486, rs4834792, rs990619, rs155364, rs480882, rs6875372, rs258951, rs1870735, rs1800795, rs12700814, rs1821002, rs3021500, rs28601761, rs7463212, rs907183, rs534523, rs520015
427
420
 
428
- You can specify several arguments. We refer to the API for a full list, but the most important one is the 'action' argument. It determines how palindromic SNPs are treated during the exposure-outcome harmonization step. Palindromic SNPs are SNPs where the nucleotide change reads the same forward and backward on complementary strands of DNA (for instance EA = 'A' and NEA = 'T').
421
+ It returns a dataframe containing the results for different MR methods:
422
+ | exposure | outcome | method | nSNP | b | se | pval |
423
+ |----------|------------|-------------------------------------------|------|----------|----------|---------------|
424
+ | SBP | Stroke_eur | Inverse-Variance Weighted | 1499 | 0.023049 | 0.001061 | 1.382645e-104 |
425
+ | SBP | Stroke_eur | Inverse Variance Weighted (Fixed Effects) | 1499 | 0.023049 | 0.000754 | 4.390655e-205 |
426
+ | SBP | Stroke_eur | Weighted Median | 1499 | 0.022365 | 0.001337 | 8.863203e-63 |
427
+ | SBP | Stroke_eur | Simple mode | 1499 | 0.027125 | 0.007698 | 4.382993e-04 |
428
+ | SBP | Stroke_eur | MR Egger | 1499 | 0.027543 | 0.002849 | 1.723156e-21 |
429
+ | SBP | Stroke_eur | Egger Intercept | 1499 | -0.001381| 0.000813 | 8.935529e-02 |
429
430
 
430
- - **action = 1**: Palindromic SNPs are not treated (assumes all alleles are on the forward strand)
431
- - **action = 2**: Uses effect allele frequencies to attempt to flip them (conservative, default)
432
- - **action = 3**: Removes all palindromic SNPs (very conservative)
431
+ You can specify several arguments. We refer to the API for a full list, but the most important one is the `action` argument. It determines how palindromic SNPs are treated during the exposure-outcome harmonization step. Palindromic SNPs are SNPs where the nucleotide change reads the same forward and backward on complementary strands of DNA (for instance `EA = 'A'` and `NEA = 'T'`).
432
+
433
+ - `action = 1`: Palindromic SNPs are not treated (assumes all alleles are on the forward strand)
434
+ - `action = 2`: Uses effect allele frequencies to attempt to flip them (conservative, default)
435
+ - `action = 3`: Removes all palindromic SNPs (very conservative)
433
436
 
434
437
  If you choose the option 2 or 3 (recommended), genal will print the list of palindromic SNPs that have been removed from the analysis.
435
438
 
436
- By default, all MR methods (inverse-variance weighted, weighted median, MR-Egger, etc.) are going to be run. But if you do not wish to run all of them, you can specify a 'methods' argument. More details in the `genal.Geno.MR` API.
439
+ By default, only some MR methods (inverse-variance weighted, weighted median, Simple mode, MR-Egger) are going to be run. But if you wish to run a different set of MR methods, you can pass a list of strings to the `methods` argument. The possible strings are:
440
+ - `IVW` for the classical Inverse-Variance Weighted method with random effects
441
+ - `IVW-RE` for the Inverse Variance Weighted method with Random Effects where the standard error is not corrected for under dispersion
442
+ - `IVW-FE` for the Inverse Variance Weighted with fixed effects
443
+ - `UWR` for the Unweighted Regression method
444
+ - `WM` for the Weighted Median method
445
+ - `WM-pen` for the penalised Weighted Median method
446
+ - `Simple-median` for the Simple Median method
447
+ - `Sign` for the Sign concordance test
448
+ - `Egger` for MR-Egger and the MR-Egger intercept
449
+ - `Egger-boot` for the bootstrapped version of MR-Egger and its intercept
450
+ - `Simple-mode` for the Simple mode method
451
+ - `Weighted-mode` for the Weighted mode method
452
+ - `all` to run all the above methods
437
453
 
438
454
  For more fine-tuning, such as settings for the number of boostrapping iterations, please refer to the API.
439
455
 
440
- If you want to visualize the obtained MR results, you can use the `genal.Geno.MR_plot` method that will plot each SNP in an effect_on_exposure x effect_on_outcome plane as well as lines corresponding to different MR methods:
456
+ If you want to visualize the obtained MR results, you can use the `genal.Geno.MR_plot` method that will plot each SNP in an `effect_on_exposure x effect_on_outcome` plane as well as lines corresponding to different MR methods:
441
457
 
442
458
  ```python
443
459
  SBP_clumped.MR_plot(filename="MR_plot_SBP_AS")
444
460
  ```
445
461
 
446
462
  ![MR plot](docs/Images/MR_plot_SBP_AS.png)
447
- You can select which MR methods you wish to plot with the 'methods' argument. Note that for an MR method to be plotted, they must be included in the latest `genal.Geno.MR` call of this `genal.Geno` instance.
463
+ You can select which MR methods you wish to plot with the `methods` argument. Note that for an MR method to be plotted, they must be included in the latest `genal.Geno.MR` call of this `genal.Geno` instance.
448
464
 
449
465
  If you wish to include the heterogeneity values (Cochran's Q) in the results, you can use the heterogeneity argument in the `genal.Geno.MR` call. Here, the heterogeneity for the inverse-variance weighted method:
450
466
 
451
467
  ```python
452
- SBP_clumped.MR(action = 3, methods = ["IVW"], exposure_name = "SBP", outcome_name = "Stroke_eur", heterogeneity = True)
468
+ SBP_clumped.MR(action = 2, methods = ["Egger","IVW"], exposure_name = "SBP", outcome_name = "Stroke_eur", heterogeneity = True)
453
469
  ```
454
470
 
455
471
  And that will give:
456
- | exposure | outcome | method | nSNP | b | se | pval | Q | Q_df | Q_pval |
457
- |----------|------------|---------------------------|------|----------|----------|---------------|-------------|------|--------------|
458
- | SBP | Stroke_eur | Inverse-Variance Weighted | 1314 | 0.023376 | 0.001131 | 7.238794e-95 | 2584.415624 | 1313 | 1.568683e-85 |
459
-
460
-
472
+ | exposure | outcome | method | nSNP | b | se | pval | Q | Q_df | Q_pval |
473
+ |----------|------------|--------------------------|------|-----------|-----------|---------------|-------------|------|--------------|
474
+ | SBP | Stroke_eur | MR Egger | 1499 | 0.027543 | 0.002849 | 1.723156e-21 | 2959.965136 | 1497 | 1.253763e-98 |
475
+ | SBP | Stroke_eur | Egger Intercept | 1499 | -0.001381 | 0.000813 | 8.935529e-02 | 2959.965136 | 1497 | 1.253763e-98 |
476
+ | SBP | Stroke_eur | Inverse-Variance Weighted| 1499 | 0.023049 | 0.001061 | 1.382645e-104 | 2965.678836 | 1498 | 4.280737e-99 |
461
477
 
462
- As expected, many MR methods indicate that SBP is strongly associated with stroke, but there are some signs of horizontal pleiotropy (instruments influencing the outcome through a different pathway than the one used as exposure) given the significant MR-Egger intercept p-value.
478
+ As expected, many MR methods indicate that SBP is strongly associated with stroke, but there could be concerns for horizontal pleiotropy (instruments influencing the outcome through a different pathway than the one used as exposure) given the almost significant MR-Egger intercept p-value.
463
479
  To investigate horizontal pleiotropy in more details, a very useful method is Mendelian Randomization Pleiotropy RESidual Sum and Outlier (MR-PRESSO). MR-PRESSO is a method designed to detect and correct for horizontal pleiotropy. It will identify which instruments are likely to be pleiotropic on their effect on the outcome, and it will rerun an inverse-variance weighted MR after excluding them. It can be run using the `genal.Geno.MRpresso` method:
464
480
 
465
481
  ```python
466
- SBP_clumped.MRpresso(action = 3)
482
+ SBP_clumped.MRpresso(action = 2, n_iterations = 30000)
467
483
  ```
468
484
 
469
485
  As with the `genal.Geno.MR` method, the `action` argument determines how the pleiotropic SNPs will be treated. The output is a list containing:
@@ -496,19 +512,19 @@ Then, it is advised to make a copy of the `genal.Geno` instance containing our i
496
512
  SBP_adjusted = SBP_clumped.copy()
497
513
  ```
498
514
 
499
- We can then call the `genal.Geno.set_phenotype` method, specifying which column contains our trait of interest (for the association testing) and which column contains the IDs:
515
+ We can then call the `genal.Geno.set_phenotype` method, specifying which column contains our trait of interest (for the association testing) and which column contains the individual IDs:
500
516
 
501
517
  ```python
502
518
  SBP_adjusted.set_phenotype(df_pheno, PHENO = "htn", IID = "IID")
503
519
  ```
504
520
 
505
- At this point, genal will identify if the phenotype is binary or quantitative (to determine the regression model. If the phenotype is binary, it will assume that the most frequent value is coding for control (and the other value for case), this can be changed with 'alternate_control=True':
521
+ At this point, genal will identify if the phenotype is binary or quantitative in order to choose the appropriate regression model. If the phenotype is binary, it will assume that the most frequent value is coding for control (and the other value for case), this can be changed with `alternate_control = True`:
506
522
 
507
523
  Detected a binary phenotype in the 'PHENO' column. Specify 'PHENO_type="quant"' if this is incorrect.
508
524
  Identified 0 as the control code in 'PHENO'. Set 'alternate_control=True' to inverse this interpretation.
509
525
  The phenotype data is stored in the .phenotype attribute.
510
526
 
511
- We can then run the association tests, specifying the path to the genetic files in plink format, and any columns we may want to include as covariates in the regression tests:
527
+ We can then run the association tests, specifying the path to the genetic files in plink format, and any columns we may want to include as covariates in the regression tests (making sure that the covariates are all numerical):
512
528
 
513
529
  ```python
514
530
  SBP_adjusted.association_test(covar=["age"], path = "path/to/genetic/files")
@@ -546,7 +562,7 @@ Genal will print information regarding the number of individuals used in the tes
546
562
  Running single-SNP logistic regression tests on tmp_GENAL/e415aab3_allchr data with adjustment for: ['age'].
547
563
  The BETA, SE, P columns of the .data attribute have been updated.
548
564
 
549
- The SBP_adjusted.data attribute has been updated in the BETA, SE, and P columns with the results of the association tests.
565
+ The `BETA`, `SE`, and `P` columns of the `SBP_adjusted.data` attribute have been updated with the results of the association tests.
550
566
 
551
567
  ### Lifting <a name="paragraph3.7"></a>
552
568
 
@@ -557,7 +573,8 @@ This can easily be done in genal using the `genal.Geno.lift` method:
557
573
  SBP_clumped.lift(start = "hg19", end = "hg38", replace = False)
558
574
  ```
559
575
 
560
- This outputs a table with the lifted SBP instruments (stored in the `SBP_clumped` instance) from build 37 (hg19) to build 38 (hg38). We specified `replace = False` to not modify the `SBP_clumped.data` attribute, but we may want to modify it (before running a PRS in a population stored in build 38 for instance). Genal will download the appropriate chain files required for the lift, and it will be done in pure python by default. However, if you plan to lift large datasets of SNPs (the whole summary statistics for instance), it may be useful to install the LiftOver executable that will run faster than the pure python version. It can be downloaded here: [https://genome-store.ucsc.edu/](https://genome-store.ucsc.edu/) You will need to create an account, scroll down to "LiftOver program", add it to your cart, and declare that you are a non-profit user.
576
+ This outputs a table with the lifted SBP instruments (stored in the `SBP_clumped` instance) from build 37 (hg19) to build 38 (hg38). We specified `replace = False` to not modify the `SBP_clumped.data` attribute, but we may want to modify it (before running a PRS in a population stored in build 38 for instance).
577
+ Genal will download the appropriate chain files required for the lift, and it will be done in python by default. However, if you plan to lift large datasets of SNPs (the whole summary statistics for instance), it may be useful to install the LiftOver executable that will run faster than the python version. It can be downloaded here: [https://genome-store.ucsc.edu/](https://genome-store.ucsc.edu/) You will need to create an account, scroll down to "LiftOver program", add it to your cart, and declare that you are a non-profit user.
561
578
 
562
579
  You can specify the path of the LiftOver executable to the `liftover_path` argument:
563
580