-
Notifications
You must be signed in to change notification settings - Fork 0
461 log normalization method #462
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| import logging | ||
|
|
||
| import pandas as pd | ||
| import numpy as np | ||
| from sklearn.preprocessing import StandardScaler | ||
|
|
||
| from backend.protzilla.data_preprocessing.plots import ( | ||
|
|
@@ -51,6 +52,7 @@ def by_z_score(protein_df: pd.DataFrame) -> dict: | |
|
|
||
| def by_median( | ||
| protein_df: pd.DataFrame, | ||
| log: bool, | ||
| percentile=0.5, # quartile, default is median | ||
| ) -> dict: | ||
| """ | ||
|
|
@@ -62,6 +64,8 @@ def by_median( | |
| :param protein_df: the dataframe that should be filtered in | ||
| long format | ||
| :type protein_df: pandas DataFrame | ||
| :param log: whether the data was log transformed before the normalisation or not | ||
| :type log: bool | ||
| :param percentile: the chosen quartile of the sample intensities for | ||
| normalisation | ||
| :type percentile: float | ||
|
|
@@ -84,17 +88,33 @@ def by_median( | |
| samples = protein_df["Sample"].unique().tolist() | ||
| zeroed_samples = [] | ||
|
|
||
| if log: | ||
| valid_mask = np.isfinite(protein_df[intensity_name]) | ||
| valid_data = protein_df.loc[valid_mask, intensity_name] | ||
| global_median = valid_data.median() | ||
|
|
||
| for sample in samples: | ||
| df_sample = protein_df.loc[protein_df["Sample"] == sample,] | ||
| quantile = df_sample[intensity_name].quantile(q=percentile) | ||
|
|
||
| if quantile != 0: | ||
| df_sample[f"Normalised {intensity_name}"] = df_sample[intensity_name].div( | ||
| quantile | ||
| ) | ||
| if log: | ||
| if np.isfinite(quantile): | ||
| # without adding the global median our data would be zero centered and therefore one half would be | ||
| # negative which can lead to problems later down the workflow | ||
| df_sample[f"Normalised {intensity_name}"] = ( | ||
| df_sample[intensity_name] - quantile + global_median | ||
| ) | ||
| else: | ||
| df_sample[f"Normalised {intensity_name}"] = 0 | ||
| zeroed_samples.append(sample) | ||
| else: | ||
| df_sample[f"Normalised {intensity_name}"] = 0 | ||
| zeroed_samples.append(sample) | ||
| if quantile != 0: | ||
| df_sample[f"Normalised {intensity_name}"] = df_sample[ | ||
| intensity_name | ||
| ].div(quantile) | ||
| else: | ||
| df_sample[f"Normalised {intensity_name}"] = 0 | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nitpick, code style: feels like the column name could be extracted to its own variable, the f-string definition is repeated for every of the 4 cases |
||
| zeroed_samples.append(sample) | ||
| df_sample.drop(axis=1, labels=[intensity_name], inplace=True) | ||
| scaled_df = pd.concat([scaled_df, df_sample], ignore_index=True) | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -644,6 +644,16 @@ def create_form(self): | |||||||||||||||||||||||||||||
| max=1, | ||||||||||||||||||||||||||||||
| step=0.1, | ||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||
| CheckboxField( | ||||||||||||||||||||||||||||||
| name="log", | ||||||||||||||||||||||||||||||
| label="Data was log-transformed before normalization", | ||||||||||||||||||||||||||||||
| value=False, | ||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||
| InfoField( | ||||||||||||||||||||||||||||||
| name="log_before_normalisation_info", | ||||||||||||||||||||||||||||||
| label="The normalisation is calculated differently for log-transformed data, " | ||||||||||||||||||||||||||||||
| "using subtraction instead of division.", | ||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||
| FormDivider("Plot settings"), | ||||||||||||||||||||||||||||||
| DropdownField( | ||||||||||||||||||||||||||||||
| name="graph_type", | ||||||||||||||||||||||||||||||
|
|
@@ -673,6 +683,14 @@ def create_form(self): | |||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| def modify_form(self, run): | ||||||||||||||||||||||||||||||
| if self.form["log"].value: | ||||||||||||||||||||||||||||||
| self.form["visual_transformation"].value = ( | ||||||||||||||||||||||||||||||
| VisualTransformations.LINEAR.value | ||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||
| elif not self.form["log"].value: | ||||||||||||||||||||||||||||||
| self.form["visual_transformation"].value = VisualTransformations.LOG10.value | ||||||||||||||||||||||||||||||
|
Comment on lines
+687
to
+692
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nitpick, code style: two comments on this - I always feel that it's more legible to first define the form fields as variables in the
Suggested change
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| calc_method = staticmethod(normalisation.by_median) | ||||||||||||||||||||||||||||||
| plot_method = staticmethod(normalisation.by_median_plot) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm assuming you did, but just to be certain: this is the behavior Chris wants for the normalization?
I tried changing the order (first doing the median normalization and then log-transformation) and the result:
is the same as if we didn't correct for the global median during the normalization (i.e.
df_sample[intensity_name] - quantileinstead ofdf_sample[intensity_name] - quantile + global_median):Just for reference, this is the output with correction enabled:

So if this is the behavior Chris wants ("the users should know this"), I feel there should at least be a warning (or another checkbox). These steps being non-commutative would be surprising to me as a user