From 5fe2dc47cdf7b6cf88d90089e4fd61f587177fee Mon Sep 17 00:00:00 2001 From: Tanushree Tunstall Date: Thu, 5 May 2022 19:44:19 +0100 Subject: [PATCH] added files and saving work --- test_data/processing_custom.py | 209 +++++++++++++++++++++++++++++ test_data/processing_v2.py | 227 ++++++++++++++++++++++++++++++++ test_data/sample_data_pivot.ods | Bin 0 -> 19411 bytes test_data/snippet_res_pnca.py | 21 +++ 4 files changed, 457 insertions(+) create mode 100644 test_data/processing_custom.py create mode 100644 test_data/processing_v2.py create mode 100644 test_data/sample_data_pivot.ods create mode 100644 test_data/snippet_res_pnca.py diff --git a/test_data/processing_custom.py b/test_data/processing_custom.py new file mode 100644 index 0000000..fd0858b --- /dev/null +++ b/test_data/processing_custom.py @@ -0,0 +1,209 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Thu Mar 24 15:01:59 2022 + +@author: tanu +""" +import sys, os +import pandas as pd +import numpy as np +from statistics import mean, median, mode +from statistics import multimode +from collections import Counter +from tidy_split import tidy_split + +#import math + +# https://stackoverflow.com/questions/43321455/pandas-count-null-values-in-a-groupby-function +# https://stackoverflow.com/questions/33457191/python-pandas-gene_LF2frame-fill-nans-with-a-conditional-mean +# round up +# int(math.ceil(mean(foo))) +# https://stackoverflow.com/questions/33457191/python-pandas-gene_LF2frame-fill-nans-with-a-conditional-mean +# https://stackoverflow.com/questions/37189878/pandas-add-column-to-groupby-gene_LF2frame +# https://stackoverflow.com/questions/43847520/how-to-get-the-distinct-count-of-values-in-a-python-pandas-gene_LF2frame +#%% Read gene_LF2 and formatting +drug = "pyrazinamide" + +gene_LF2 = pd.read_csv("/home/tanu/git/ML_AI_training/test_gene_LF2/sample_gene_LF2.csv") +gene_LF2.columns + +gene_LF2.head() +#%% Quick checks: Lineage and sample count for each mutation +gene_LF2['id'].nunique() +gene_LF2['mutationinformation'].nunique() +total_id_ucount = gene_LF2['id'].nunique() +total_id_ucount + +gene_LF2.groupby('mutationinformation')['lineage'].size() +gene_LF2.groupby('mutationinformation')['lineage_corrupt'].size() +gene_LF2.groupby('mutationinformation')['id'].size() +gene_LF2.groupby('mutationinformation')['lineage'].value_counts() +gene_LF2.groupby('mutationinformation')['lineage'].nunique() +#%% id count: add all id ids and count of unique ids per mutation +gene_LF2['id_list'] = gene_LF2['mutationinformation'].map(gene_LF2.groupby('mutationinformation')['id'].apply(list)) +gene_LF2['id_ucount'] = gene_LF2['mutationinformation'].map(gene_LF2.groupby('mutationinformation')['id'].nunique()) +gene_LF2[['mutationinformation', 'id', 'id_list', 'id_ucount']] +#%% Lineages: add all lineages and count of unique lineages per mutation +# Lineages good: lineage column has only a single lineage for each mutationinformation +gene_LF2['lineage'] +gene_LF2['lineage_list'] = gene_LF2['mutationinformation'].map(gene_LF2.groupby('mutationinformation')['lineage'].apply(list)) +gene_LF2['lineage_ucount'] = gene_LF2['mutationinformation'].map(gene_LF2.groupby('mutationinformation')['lineage'].nunique()) +gene_LF2[['mutationinformation', 'lineage', 'lineage_list', 'lineage_ucount']] + +# Lineage corrupt: lineage column has only multiple lineages for each mutationinformation separated by ';' +gene_LF2['lineage_corrupt'] +# split using tidy_split() +gene_LF2_split = tidy_split(gene_LF2, 'lineage_corrupt', sep = ';') +# remove leading white space else these are counted as distinct mutations as well +#gene_LF2_split['lineage_corrupt'] = gene_LF2_split['lineage_corrupt'].str.lstrip() +gene_LF2_split['lineage_corrupt'] = gene_LF2_split['lineage_corrupt'].str.strip() +gene_LF2_split.head() + +gene_LF2_split['lineage_corrupt_list'] = gene_LF2_split['mutationinformation'].map(gene_LF2_split.groupby('mutationinformation')['lineage_corrupt'].apply(list)) +gene_LF2_split['lineage_corrupt_ucount'] = gene_LF2_split['mutationinformation'].map(gene_LF2_split.groupby('mutationinformation')['lineage_corrupt'].nunique()) + +gene_LF2_split[['mutationinformation', 'lineage_corrupt_list', 'lineage_corrupt_ucount']] +gene_LF2_split[['mutationinformation', 'lineage_ucount', 'lineage_corrupt_ucount']] + +#%% AF: calculate AF for each mutation +#1) calculate no. of unique ids +gene_LF2['id_ucount']/total_id_ucount + +#%% DM OM labels +# COPY mutation_info_labels column +gene_LF2['mutation_info_labels_orig'] = gene_LF2['mutation_info_labels'] + +# Convert DM/OM labels to numeric +dm_om_map = {'DM': 1, 'OM': 0} # pnca, OM is minority, other genes: DM is minority +gene_LF2['dm_om_numeric'] = gene_LF2['mutation_info_labels'].map(dm_om_map) +# sanity check +gene_LF2['dm_om_numeric'].value_counts() +gene_LF2['mutation_info_labels'].value_counts() + +# Convert drtype column to numeric +drtype_map = {'XDR': 5 + , 'Pre-XDR': 4 + , 'MDR': 3 + , 'Pre-MDR': 2 + , 'Other': 1 + , 'Sensitive': 0} + +gene_LF2['drtype_numeric'] = gene_LF2['drtype'].map(drtype_map) + +# COPY dst column +gene_LF2['dst'] = gene_LF2[drug] # to allow cross checking +gene_LF2['dst_multimode'] = gene_LF2[drug] + +# sanity check +gene_LF2[drug].value_counts() +gene_LF2['dst_multimode'].value_counts() + +gene_LF2[drug].isnull().sum() +gene_LF2['dst_multimode'].isnull().sum() + +gene_LF2['mutationinformation'].value_counts() +#gene_LF2.C.isnull().groupby([df['A'],df['B']]).sum().astype(int).reset_index(name='count') +gene_LF2[drug].isnull().groupby(gene_LF2['mutationinformation']).sum() + +# GOAL is to populate na in the dst column from the count of the dm_om_numeric column +gene_LF2['dst_multimode'].isnull().groupby(gene_LF2['mutationinformation']).sum() + +gene_LF2['mutationinformation'] + +#%% Recalculating dst: my gene_LF2 +#------------------------------ +# Revised dst: max(multimode) +#------------------------------ +# For each mutation, generate the revised dst which is the mode of dm_om_numeric +# PROBLEM: Returns the smallest of the two when bimodal, and fails when all equally likely +# SOLUTION: Using max of the 'dst_noNA' column +#gene_LF22.groupby('mutationinformation')['dm_om_numeric'].agg(multimode) + +# Get multimode for dm_om_numeric column +dm_om_multimode = gene_LF2.groupby('mutationinformation')['dm_om_numeric'].agg(multimode) +#dm_om_multimode + +# Fill using multimode ONLY where NA in dst_multimode column +#gene_LF22['dst_multimode'] = gene_LF22['dst_multimode'].fillna(dm_om_multimode) +gene_LF2['dst_multimode'] = gene_LF2['dst_multimode'].fillna(dm_om_multimode) + +# gene_LF22['dst_multimode'] + +# Now get the max from multimode +gene_LF22['dst_noNA'] = gene_LF2['dst_multimode'].apply(lambda x: np.nanmax(x)) +print(gene_LF2) + +# Finally created a revised dst with the max from the multimode +gene_LF22['dst_mode'] = gene_LF2.groupby('mutationinformation')['dst_noNA'].max() +#============================================================================== +#%% Recalculating drtype: my gene_LF2 +#-------------------------------- +# drtype: ALL values: +# numeric and names in an array +#-------------------------------- +gene_LF2['drtype_all_vals'] = gene_LF2['drtype_numeric'] +gene_LF2['drtype_all_names'] = gene_LF2['drtype'] + +# example: https://stackoverflow.com/questions/55125680/pandas-get-all-groupby-values-in-an-array +# print(df.groupby('key').gene_LF2.apply(list).reset_index()) # my use case, don't need the reset_index() +gene_LF2['drtype_all_vals'] = gene_LF2.groupby('mutationinformation').drtype_all_vals.apply(list) +gene_LF2['drtype_all_names'] = gene_LF2.groupby('mutationinformation').drtype_all_names.apply(list) + +#--------------------------------- +# Revised drtype: max(Multimode) +#-------------------------------- +gene_LF2['drtype_multimode'] = gene_LF2.groupby(['mutationinformation'])['drtype_numeric'].agg(multimode) +gene_LF2['drtype_multimode'] + +# Now get the max from multimode +gene_LF2['drtype_mode'] = gene_LF2['drtype_multimode'].apply(lambda x: np.nanmax(x)) +gene_LF2.head() + +#---------------------- +# Revised drtype: Max +#---------------------- +gene_LF2.head() +gene_LF2['drtype_max'] = gene_LF2.groupby(['mutationinformation'])['drtype_numeric'].max() +#gene_LF2 = gene_LF22.reset_index() +gene_LF2.head() + +#%% Finally reset index +gene_LF2 = gene_LF2.reset_index() +#============================================================================== +#--------------------------------------- +# Create revised mutation_info_column +#--------------------------------------- +gene_LF2['dst_mode'].value_counts() +gene_LF2[drug].value_counts() + +# note this is overriding, since downstream depends on it +# make a copy you if you need to keep that +gene_LF2['mutation_info_labels_orig'] = gene_LF2['mutation_info_labels'] +gene_LF2['mutation_info_labels'] = gene_LF2['dst_mode'].map({1: 'DM' + , 0: 'OM'}) +gene_LF2['mutation_info_labels_orig'].value_counts() +gene_LF2['mutation_info_labels'].value_counts() +#============================================================================== +# sanity check +if (all(gene_LF2['mutation'] == gene_LF2['mutationinformation'])): + print('\nPass: Mutationinformation check successful') +else: + sys.exit('\nERROR: mutationin cross checks failed. Please check your group_by() aggregate functions') + +# Drop mutation column +gene_LF2.drop(['mutation'], axis=1, inplace=True) +#%% subset: equivalent of merged_df3? +# https://stackoverflow.com/questions/39900061/sort-lists-in-a-pandas-gene_LF2frame-column + +# result = gene_LF2['dst_multimode'].sort_values().apply(lambda x: sorted(x)) +# newdf = pd.gene_LF2Frame({'dst_multimode': Series(list(set(result['a'].apply(tuple))))}) +# newdf.sort_values(by='a') + +# gene_LF2['dst_multimode'].value_counts() +# gene_LF2.sort_values(['dst_multimode'], ascending=False) + +#gene_LF2_df3 = gene_LF2.drop_duplicates(['mutationinformation']) +#gene_LF2_df3_v2 = gene_LF2.drop_duplicates(['mutationinformation']) +#all(gene_LF2_df3 == gene_LF2_df3_v2) +#%% diff --git a/test_data/processing_v2.py b/test_data/processing_v2.py new file mode 100644 index 0000000..ad7180e --- /dev/null +++ b/test_data/processing_v2.py @@ -0,0 +1,227 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Thu Mar 24 15:01:59 2022 + +@author: tanu +""" +import sys, os +import pandas as pd +import numpy as np +from statistics import mean, median, mode +from statistics import multimode +from collections import Counter +from tidy_split import tidy_split + +#import math + +# https://stackoverflow.com/questions/43321455/pandas-count-null-values-in-a-groupby-function +# https://stackoverflow.com/questions/33457191/python-pandas-dataframe-fill-nans-with-a-conditional-mean +# round up +# int(math.ceil(mean(foo))) +# https://stackoverflow.com/questions/33457191/python-pandas-dataframe-fill-nans-with-a-conditional-mean +# https://stackoverflow.com/questions/37189878/pandas-add-column-to-groupby-dataframe +# https://stackoverflow.com/questions/43847520/how-to-get-the-distinct-count-of-values-in-a-python-pandas-dataframe +#%% Read data and formatting +drug = "pyrazinamide" + +data = pd.read_csv("/home/tanu/git/ML_AI_training/test_data/sample_data.csv") +data.columns + +data.head() +#%% Quick checks: Lineage and sample count for each mutation +data['id'].nunique() +data['mutationinformation'].nunique() +total_id_ucount = data['id'].nunique() +total_id_ucount + +data.groupby('mutationinformation')['lineage'].size() +data.groupby('mutationinformation')['lineage_corrupt'].size() +data.groupby('mutationinformation')['id'].size() +data.groupby('mutationinformation')['lineage'].value_counts() +data.groupby('mutationinformation')['lineage'].nunique() +#%% id count: add all id ids and count of unique ids per mutation +data['id_list'] = data['mutationinformation'].map(data.groupby('mutationinformation')['id'].apply(list)) +data['id_ucount'] = data['mutationinformation'].map(data.groupby('mutationinformation')['id'].nunique()) +data[['mutationinformation', 'id', 'id_list', 'id_ucount']] +#%% Lineages: add all lineages and count of unique lineages per mutation +# Lineages good: lineage column has only a single lineage for each mutationinformation +data['lineage'] +data['lineage_list'] = data['mutationinformation'].map(data.groupby('mutationinformation')['lineage'].apply(list)) +data['lineage_ucount'] = data['mutationinformation'].map(data.groupby('mutationinformation')['lineage'].nunique()) +data[['mutationinformation', 'lineage', 'lineage_list', 'lineage_ucount']] + +# Lineage corrupt: lineage column has only multiple lineages for each mutationinformation separated by ';' +data['lineage_corrupt'] +# split using tidy_split() +data_split = tidy_split(data, 'lineage_corrupt', sep = ';') +# remove leading white space else these are counted as distinct mutations as well +#data_split['lineage_corrupt'] = data_split['lineage_corrupt'].str.lstrip() +data_split['lineage_corrupt'] = data_split['lineage_corrupt'].str.strip() +data_split.head() + +data_split['lineage_corrupt_list'] = data_split['mutationinformation'].map(data_split.groupby('mutationinformation')['lineage_corrupt'].apply(list)) +data_split['lineage_corrupt_ucount'] = data_split['mutationinformation'].map(data_split.groupby('mutationinformation')['lineage_corrupt'].nunique()) + +data_split[['mutationinformation', 'lineage_corrupt_list', 'lineage_corrupt_ucount']] +data_split[['mutationinformation', 'lineage_ucount', 'lineage_corrupt_ucount']] + +#%% AF: calculate AF for each mutation +#1) calculate no. of unique ids +data['id_ucount']/total_id_ucount + +#%% DM OM labels +# COPY mutation_info_labels column +data['mutation_info_labels_orig'] = data['mutation_info_labels'] + +# Convert DM/OM labels to numeric +dm_om_map = {'DM': 1, 'OM': 0} # pnca, OM is minority, other genes: DM is minority +data['dm_om_numeric'] = data['mutation_info_labels'].map(dm_om_map) +# sanity check +data['dm_om_numeric'].value_counts() +data['mutation_info_labels'].value_counts() + +# Convert drtype column to numeric +drtype_map = {'XDR': 5 + , 'Pre-XDR': 4 + , 'MDR': 3 + , 'Pre-MDR': 2 + , 'Other': 1 + , 'Sensitive': 0} + +data['drtype_numeric'] = data['drtype'].map(drtype_map) + +# COPY dst column +data['dst'] = data[drug] # to allow cross checking +data['dst_multimode'] = data[drug] + +# sanity check +data[drug].value_counts() +data['dst_multimode'].value_counts() + +data[drug].isnull().sum() +data['dst_multimode'].isnull().sum() + +data['dst_multimode'] + +data['mutationinformation'].value_counts() +data[drug].isnull().groupby(data['mutationinformation']).sum() + +# GOAL is to populate na in the dst column from the count of the dm_om_numeric column +data['dst_multimode'].isnull().groupby(data['mutationinformation']).sum() + +# COPY mutationinformation for sanity check +data['mutation'] = data['mutationinformation'] + +#%% POC continued: Test getting mode +#data.groupby('mutationinformation')['dm_om_numeric'].mode() +data.groupby('mutationinformation')['dm_om_numeric'].agg(mode) +data.groupby('mutationinformation')['dm_om_numeric'].agg(multimode) +foo = data.groupby('mutationinformation')['dm_om_numeric'].agg(multimode) +foo +foo = foo.to_frame() +foo['dm_om_numeric'].apply(lambda x: max(x))# returns nan +foo['dm_om_numeric'].apply(lambda x: np.nanmax(x)) +#foo.assign(dst_mode = lambda x: (x['dst'])) +foo['multimode_extract'] = foo['dm_om_numeric'].apply(lambda x: max(x)) +foo['multimode_extract'] +#%% Recalculating columns [dst, drtype and mutation_info_labels]: SET Index as 'mutationinformation' +data2 = data.copy() +# Reset index as it allows the groupby expression to directly map +data2 = data2.set_index(['mutationinformation']) +#%% Recalculating dst: my data +#------------------------------ +# Revised dst: max(multimode) +#------------------------------ +# For each mutation, generate the revised dst which is the mode of dm_om_numeric +# PROBLEM: Returns the smallest of the two when bimodal, and fails when all equally likely +# SOLUTION: Using max of the 'dst_noNA' column +#data2.groupby('mutationinformation')['dm_om_numeric'].agg(multimode) + +# Get multimode for dm_om_numeric column +dm_om_multimode = data2.groupby('mutationinformation')['dm_om_numeric'].agg(multimode) +dm_om_multimode + +# Fill using multimode ONLY where NA in dst_multimode column +#data2['dst_multimode'] = data2['dst_multimode'].fillna(dm_om_multimode) +data2['dst_multimode'] = data2['dst_multimode'].fillna(dm_om_multimode) + +# data2['dst_multimode'] + +# Now get the max from multimode +data2['dst_noNA'] = data2['dst_multimode'].apply(lambda x: np.nanmax(x)) +print(data2) + +# Finally created a revised dst with the max from the multimode +data2['dst_mode'] = data2.groupby('mutationinformation')['dst_noNA'].max() +#============================================================================== +#%% Recalculating drtype: my data +#-------------------------------- +# drtype: ALL values: +# numeric and names in an array +#-------------------------------- +data2['drtype_all_vals'] = data2['drtype_numeric'] +data2['drtype_all_names'] = data2['drtype'] + +# example: https://stackoverflow.com/questions/55125680/pandas-get-all-groupby-values-in-an-array +# print(df.groupby('key').data.apply(list).reset_index()) # my use case, don't need the reset_index() +data2['drtype_all_vals'] = data2.groupby('mutationinformation').drtype_all_vals.apply(list) +data2['drtype_all_names'] = data2.groupby('mutationinformation').drtype_all_names.apply(list) + +#--------------------------------- +# Revised drtype: max(Multimode) +#-------------------------------- +data2['drtype_multimode'] = data2.groupby(['mutationinformation'])['drtype_numeric'].agg(multimode) +data2['drtype_multimode'] + +# Now get the max from multimode +data2['drtype_mode'] = data2['drtype_multimode'].apply(lambda x: np.nanmax(x)) +data2.head() + +#---------------------- +# Revised drtype: Max +#---------------------- +data2.head() +data2['drtype_max'] = data2.groupby(['mutationinformation'])['drtype_numeric'].max() +#data2 = data2.reset_index() +data2.head() + +#%% Finally reset index +data2 = data2.reset_index() +#============================================================================== +#--------------------------------------- +# Create revised mutation_info_column +#--------------------------------------- +data2['dst_mode'].value_counts() +data2[drug].value_counts() + +# note this is overriding, since downstream depends on it +# make a copy you if you need to keep that +data2['mutation_info_labels_orig'] = data2['mutation_info_labels'] +data2['mutation_info_labels'] = data2['dst_mode'].map({1: 'DM' + , 0: 'OM'}) +data2['mutation_info_labels_orig'].value_counts() +data2['mutation_info_labels'].value_counts() +#============================================================================== +# sanity check +if (all(data2['mutation'] == data2['mutationinformation'])): + print('\nPass: Mutationinformation check successful') +else: + sys.exit('\nERROR: mutationin cross checks failed. Please check your group_by() aggregate functions') + +# Drop mutation column +data2.drop(['mutation'], axis=1, inplace=True) +#%% subset: equivalent of merged_df3? +# https://stackoverflow.com/questions/39900061/sort-lists-in-a-pandas-dataframe-column + +# result = data2['dst_multimode'].sort_values().apply(lambda x: sorted(x)) +# newdf = pd.DataFrame({'dst_multimode': Series(list(set(result['a'].apply(tuple))))}) +# newdf.sort_values(by='a') + +# data2['dst_multimode'].value_counts() +# data2.sort_values(['dst_multimode'], ascending=False) + +#data_df3 = data2.drop_duplicates(['mutationinformation']) +#data_df3_v2 = data2.drop_duplicates(['mutationinformation']) +#all(data_df3 == data_df3_v2) +#%% \ No newline at end of file diff --git a/test_data/sample_data_pivot.ods b/test_data/sample_data_pivot.ods new file mode 100644 index 0000000000000000000000000000000000000000..d1e2394894ad0a05cf9dadedc1d3b4f00e6cfcce GIT binary patch literal 19411 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 literal 0 HcmV?d00001 diff --git a/test_data/snippet_res_pnca.py b/test_data/snippet_res_pnca.py new file mode 100644 index 0000000..e92f7c2 --- /dev/null +++ b/test_data/snippet_res_pnca.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Thu Apr 21 14:54:26 2022 + +@author: tanu +""" +RESULTS: +Total WT in dr_muts_col: 30761 +Total matches of pncA SNP matches in dr_mutations_pyrazinamide : 3973 +Total samples with > 1 pncA nsSNPs in dr_muts_col: 73 +Total matches of UNIQUE pncA SNP matches in dr_mutations_pyrazinamide : 227 +=================================================================RESULTS: +Total WT in other_muts_col: 31653 +Total matches of pncA SNP matches in other_mutations_pyrazinamide : 943 +Total samples with > 1 pncA nsSNPs in other_muts_col: 14 +Total matches of UNIQUE pncA SNP matches in other_mutations_pyrazinamide : 200 +================================================================= + +# First copy index colum +# then use the Vcounts analogy for counts