From 9cdbadfb64ecdc0c88bfdd3b5659ae3e93957591 Mon Sep 17 00:00:00 2001 From: npg2108 Date: Mon, 23 Apr 2018 14:54:52 -0400 Subject: [PATCH] First commit --- README.md | 34 + cohorts/__init__.py | 10 + cohorts/cohort.py | 1244 ++++++++++++++++++++++++++ cohorts/utils.py | 248 ++++++ setup.py | 10 + test.ipynb | 2040 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 3586 insertions(+) create mode 100644 README.md create mode 100644 cohorts/__init__.py create mode 100644 cohorts/cohort.py create mode 100644 cohorts/utils.py create mode 100644 setup.py create mode 100644 test.ipynb diff --git a/README.md b/README.md new file mode 100644 index 0000000..48fdf23 --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +# `Cohorts` + +### A python package for standardized and reproducible processing, analysis, and integration of clinical proteomics data + +Written by Nicholas Giangreco + +Copyright (c) 2018 by the Tatonetti Lab + +## Goal + +Discovery of disease biomarkers or risk factors requires high throughput experimentation on patient's samples collected as a cohort of patients. This clinical data is collected from multiple patient cohorts either within an institutions or among many institutions. + +This python package aims to provide standardization in creating a data structure representing each clinical dataset, while allowing for seamless integration of multiple instances. + + +## Installation + +git clone ... +cd ... +pip install setup.py +... + +### Prerequisites + +python 3 + +## Contribute + +Please do! Both cohort data structure and functionality features are needed. + +## License + + + diff --git a/cohorts/__init__.py b/cohorts/__init__.py new file mode 100644 index 0000000..8a91a85 --- /dev/null +++ b/cohorts/__init__.py @@ -0,0 +1,10 @@ +''' +Cohorts : Enabling standardized and reproducible clinical 'omics analysis +========================================================================= + +This packages allows handling and structuring datasets from patient cohorts. + + +''' + +from .cohort import Cohort \ No newline at end of file diff --git a/cohorts/cohort.py b/cohorts/cohort.py new file mode 100644 index 0000000..bf3d884 --- /dev/null +++ b/cohorts/cohort.py @@ -0,0 +1,1244 @@ +from .utils import * +import os +import numpy as np +import pandas as pd +import scipy.stats as sc +from sklearn.preprocessing import StandardScaler +import itertools as it + +class Cohort(object): + """ + Patient cohort object for patient proteomics data. + + Dataframes, variables, and functions facilitating the processing, analysis, and integration of the cohort data. + + Parameters + ---------- + cohort: str + name of the patient cohort + + file_dir: str + directory where replicate dataframe and + sample group membership dataframe file names are located + + replicates_file: str + name of the replicates dataframe file + + A proteins x B replicates + tab delimited + + replicate = "SampleName" + "_Rep[0-9]" + + sample_groups_file: str + name of the sample group file + + N groups x M samples + + sample = "SampleName" + + data_dir: str + directory where extra data files are located + + uniprot_file: str + name of the uniprot database flat file located in data_dir + + Examples + -------- + >>>c = cohorts.Cohort(cohort='cohort_name', + file_dir="path/to/files/" + replicates_file="file_name", + sample_groups_file="sample_groups_file_name", + data_dir="path/to/data/dir/", + uniprot_file="uniprot_flat_file" + ) + >>>c.set_replicates_hq() + >>>c.set_trans_replicates_hq() + >>>c.set_samples_hq() + >>>c.set_trans_samples_hq() + + """ + + tests = [ + ( "t-test",sc.ttest_ind ), + ("Wilcoxon_RankSum_test",sc.ranksums) + ] + + + def __init__(self,cohort='cumc', + replicates_file=None,sample_groups_file=None, + uniprot_file=None, + file_dir="",data_dir="../../data/"): + + self.cwd = os.getcwd() + self.data_dir = data_dir + self.file_dir = file_dir + self.cohort = cohort + self.replicates_file = replicates_file + self.sample_groups_file = sample_groups_file + self.uniprot_file = uniprot_file + self.raw_samples = None + self.raw_replicates = None + self.replicates_hq = None + self.trans_replicates_hq = None + self.samples_hq = None + self.trans_samples_hq = None + self.sample_replicate_dictionary = None + self.samples = None + self.replicates = None + self.proteins = None + self.replicate_groups = None + self.sample_groups = None + self.tidy_replicate_groups = None + self.tidy_sample_groups = None + self.groups = None + self.ref = None + self.treat = None + self.set_replicates_file() + self.set_sample_groups_file() + self.set_raw_replicates() + self.set_replicates() + self.set_sample_replicate_dictionary() + self.set_samples() + self.set_sample_groups() + self.set_replicate_groups() + self.set_raw_samples() + self.set_tidy_sample_groups() + self.set_tidy_replicate_groups() + self.set_proteins() + self.set_groups() + self.set_ref() + self.set_treat() + + #extra parameters/data objects that can be + #attributed to an object instance + self.data = {} + self.params = {} + + + #SET FUNCTIONS + + def set_replicates_file(self): + """ + Setting the replicates file string. + Combination of the file directory string and the replicates file string + + Parameters + ---------- + None + + """ + + self.replicates_file = str(self.file_dir) + str(self.replicates_file) + + def set_sample_groups_file(self): + """ + Setting the replicate_groups string + Combination of the path string and the replicates file string + + Parameters + ---------- + None + + """ + self.sample_groups_file = str(self.file_dir) + str(self.sample_groups_file) + + def set_uniprot_file(self): + """ + Setting the path to the uniprot flat file + + Parameters + ---------- + None + + """ + self.uniprot_file = str(self.data_dir) + str(self.uniprot_file) + + def set_raw_replicates(self): + """ + Setting raw replicate dataframe from files given to object + + Parameters + ---------- + None + + """ + self.raw_replicates = pd.read_csv(self.replicates_file,delimiter="\t",index_col=0) + + def set_replicates(self): + """ + Setting replicate names + + Depends on : raw_replicates + + Parameters + ---------- + None + + """ + + self.replicates = self.raw_replicates.columns.tolist() + + def set_sample_replicate_dictionary(self): + """ + Setting dictionary of samples (keys) to replicates (values) + + Depends on : replicates + + Parameters + ---------- + None + + """ + + #get replicates + replicates = self.replicates + + #strip replicate indicator to get array of sample names for replicates + duplicate_samples = [y[0] for y in [x for x in np.chararray.split(replicates,"_")]] + + #set previous to series for easy unique sample name retrieval + samples = pd.Series(duplicate_samples).unique() + + #initialize dictionary + dictionary = {} + + #loop through unique samples + for key in samples: + #get indice of replicates for sample + replicate_inds = pd.Series(duplicate_samples).isin([key]) + + #get replicates for sample + values = np.array(replicates)[replicate_inds.tolist()] + + #set key:value pair (sample : replicates) in dictionary + dictionary[key] = values.tolist() + + self.sample_replicate_dictionary = dictionary + + def set_raw_samples(self,agg='mean'): + """ + Setting raw sample dataframe + + Take statistic of replicates with particular sample membership + + Depends on : raw_replicates and make_df_samples() + + Parameters + ---------- + + agg: {'mean','median', 'variance'} + statistic to apply to replicate values for sample membership + + """ + + df = self.raw_replicates.fillna(0) + + self.raw_samples = self.make_df_samples(df,agg=agg) + + def set_replicates_hq(self, + uniprot_annot=False, + annot_status='reviewed', + quant_least_reps_per_samps=False, + n_reps=1, + all_reps_quant=False, + threshold=88, + intrasamp_var=False, + higher=False): + """ + Setting proteins in raw dataframe to be reviewed by Uniprot + + Depends on : raw_replicates, proteins_in_n_replicates_per_samples, proteins_quant_all_reps, proteins_with_uniprot_annot, proteins_by_intrasample_variability + + Parameters + ---------- + + uniprot_annot {True,False} + Subset proteins by annot=ation status in uniprot database + annot_status {'reviewed','unreviewed'} + Annotation status in uniprot + quant_least_reps_per_samps {True,False} + Subset proteins by the number of replicates quantified per sample + n_reps + Number of replicates quantified per sample. See above + all_reps_quant {True,False} + Subset proteins by only those quantified in every replicate per sample + intrasamp_var {True,False} + Subset proteins by the amount of replicate variance per sample + threshold + Quantile to subset variance from. See above + higher {True,False} + Indicates whether to subset by proteins with a high annotation score from Uniprot + + """ + + #get raw data + df = self.raw_replicates.fillna(0) + + #subset to have proteins found in atleast sufficient_reps + #per sample for all samples + if quant_least_reps_per_samps: + prots = self.proteins_in_n_replicates_per_samples(df,n_reps=1) + df = df.loc[prots] + + #subset to have proteins found in atleast n_reps + #per sample for all samples + if all_reps_quant: + prots = self.proteins_quant_all_reps(df) + df = df.loc[prots] + + #subset to have proteins with high annotation score + if uniprot_annot: + #set uniprot file if asked for, for protein filtering + self.set_uniprot_file() + prots = self.proteins_with_uniprot_annot(df,status=annot_status) + df = df.loc[prots] + + # subset to have proteins with certain intrasample variability + if intrasamp_var: + + prots = self.proteins_by_intrasample_variability(df, + higher=higher, + threshold=threshold) + df = df.loc[prots] + + self.replicates_hq = df + + def set_trans_replicates_hq(self, + trans='None', + add_small=False, + stat_thresh=False, + threshold=95, + higher=False, + statistic='variance'): + """ + Transforming hq values with different functions, by default log1p. + + Depends on : replicates_hq, proteins_by_statistic_threshold + + Parameters + ---------- + + trans: numerical transformation. Default: scikitlearn's StandardScaler + Indicates how to transform the raw protein values + add_small + Add small value if any dataframe value is 0 - when log transforming + stat_threshold + Subsetting dataframe by a statistic threshold + threshold [0,100] + Quantile for statistic threshold + higher + Subset above or below statistic threshold + statistic {'mean','median','variance'} + Statistic to be applied + + """ + + #set hq dataframe; make sure there's no NaN values + df = self.replicates_hq + + #instantiate/declare/set up Standard scaler model from + #scikitlearn on data + scaler = StandardScaler() + scaler.fit(df) + + #list of name-function pairs + func = [('log1p', np.log1p), + ('log2', np.log2), + ('sklearn', scaler.transform), + ('rank_normalize', rank_normalize), + ('quantile_normalize', quantileNormalize), + ('None', pd.DataFrame.copy)] + + #get appropriate list index for function from trans string + m = [x for x in range(len(func)) if trans in func[x][0]][0] + + #add small epsilon value to all protein values + if add_small: + eps = 0.0001 + df = df.applymap(lambda x : x + eps) + + #apply function from appropriate function list index + data = pd.DataFrame(func[m][1](df), + index=df.index, + columns=df.columns + ) + + #subset to have proteins that meet a certain statistical threshold + if stat_thresh: + prots = self.proteins_by_statistic_threshold(data, + statistic=statistic, + threshold=threshold, + higher=higher) + data = data.loc[prots] + + self.trans_replicates_hq = data + + def set_samples_hq(self, + agg='mean', + uniprot_annot=False, + annot_status='reviewed'): + """ + Setting sample dataframe from processed replicate dataframe + + Depends on : trans_replicates_hq, make_df_samples + Parameters + ---------- + + agg: {'mean','median', 'variance'} + statistic to apply to replicate values for sample membership + uniprot_annot {True,False} + Subset proteins by annot=ation status in uniprot database + annot_status {'reviewed','unreviewed'} + Annotation status in uniprot + """ + + #get processed replicates + df = self.trans_replicates_hq + + #subset to have proteins with high annotation score + if uniprot_annot: + #set uniprot file if asked for, for protein filtering + self.set_uniprot_file() + prots = self.proteins_with_uniprot_annot(df,status=annot_status) + df = df.loc[prots] + + self.samples_hq = self.make_df_samples( df , agg = agg ) + + def set_trans_samples_hq(self, + trans='None', + add_small=False, + stat_thresh=False, + threshold=95, + higher=False, + statistic='variance'): + """ + Transforming hq values with different functions, by default log1p. + + Depends on : samples_hq, proteins_by_statistic_threshold + + Parameters + ---------- + + trans: numerical transformation. Default: scikitlearn's StandardScaler + Indicates how to transform the raw protein values + add_small + Add small value if any dataframe value is 0 - when log transforming + stat_threshold + Subsetting dataframe by a statistic threshold + threshold [0,100] + Quantile for statistic threshold + higher + Subset above or below statistic threshold + statistic {'mean','median','variance'} + Statistic to be applied + + """ + + #set hq dataframe; make sure there's no NaN values + data = self.samples_hq + + #instantiate/declare/set up Standard scaler model from + #scikitlearn on data + scaler = StandardScaler() + scaler.fit(data) + + #only do log (other than log1p) transformations if values are + #all nonzero + if len(np.where(data.as_matrix().ravel()==0)[0])>0: + add_small = True + print('There are zero values in the sample dataframe, a small number epsilon must be added to the protein values when there are zero values. Adding small epsilon...') + + #list of name-function pairs + func = [('log1p', np.log1p), + ('log2', np.log2), + ('sklearn', scaler.transform), + ('rank_normalize', rank_normalize), + ('quantile_normalize', quantileNormalize), + ('None', pd.DataFrame.copy)] + + #get appropriate list index for function from trans string + m = [x for x in range(len(func)) if trans in func[x][0]][0] + + #add small epsilon value to all protein values + if add_small: + eps = 0.0001 + data = data.applymap(lambda x : x + eps) + + #apply function from appropriate function list index + data = pd.DataFrame(func[m][1](data), + index=data.index, + columns=data.columns + ) + + #subset to have proteins that meet a certain statistical threshold + if stat_thresh: + prots = self.proteins_by_statistic_threshold(data, + statistic=statistic, + threshold=threshold, + higher=higher) + data = data.loc[prots] + + self.trans_samples_hq = data + + def set_samples(self): + """ + Setting patient names from raw dataframe + + Depends on : sample_replicate_dictionary + + Parameters + ---------- + None + + """ + self.samples = [x for x in self.sample_replicate_dictionary.keys()] + + def set_proteins(self): + """ + Setting protein ids from raw dataframe + + Depends on raw_replicates + + Parameters + ---------- + None + + """ + self.proteins = self.raw_replicates.index.values + + def set_sample_groups(self,file=None): + """ + Setting group membership of samples dataframe where 1 indicates membership and 0 no membership. + + Parameters + ---------- + file + file to read sample groups data. Defaults to parameters from cohorts instantiation + """ + + #if file is not None: + + self.sample_groups = pd.read_csv(self.sample_groups_file,delimiter="\t",index_col=0) + + def set_df_replicate_groups(self): + """ + Aggregating df_replicate_groups to derive sample group + membership + + Parameters + ---------- + None + + """ + + mats = {} + for samp in self.samples: + single = self.sample_groups.loc[:,samp] + reps = self.sample_replicate_dictionary[samp] + for r in reps: + mats[r] = single + + return pd.DataFrame.from_dict(mats) + + def set_replicate_groups(self,file=None): + """ + Setting group membership of replicate dataframe where 1 indicates membership and 0 no membership. + + Parameters + ---------- + file + file to read replicate groups data. Defaults to parameters from cohorts instantiation + + """ + + self.replicate_groups = self.set_df_replicate_groups() + + def set_groups(self): + """ + Setting groups from sample groups dataframe + + Parameters + ---------- + None + + """ + + self.groups = self.sample_groups.index.values + + def set_ref(self,ref='NL'): + """ + Setting reference group (hard coded to be normal patients or 'NL', but can change this after declaration) + + Parameters + ---------- + + ref: string + Reference group name + + + """ + + #get ref index + ind = np.where(self.groups==ref)[0] + + #make sure there's only one trt name in all groups + if len(ind)==1: + + self.ref = self.groups[ind] + + else: + + self.ref = np.asarray(self.groups[0],dtype='object') + + def set_treat(self,trt='PGD'): + """ + Setting treatment group + + Parameters + ---------- + + trt: string + Treatment group name + """ + + #get trt index + ind = np.where(self.groups==trt)[0] + + #make sure there's only one trt name in all groups + if len(ind)==1: + + self.treat = self.groups[ind] + else: + + self.treat = np.asarray(self.groups[1],dtype='object') + + def set_tidy_replicate_groups(self): + """ + Setting tidy group membership of replicates, where each replicate is the observation and group membership is an attribute (column) + + Parameters + ---------- + None + + """ + + #copy sample groups dataframe + df = self.replicate_groups.T.copy() + + #set Replicates as column in dataframe + df.loc[:,'Replicates'] = df.index + + #melt to tidy dataframe + melted = pd.melt(df, + id_vars=['Replicates'], + value_vars=df.columns.tolist()[0:len(df.columns)-1], + var_name='Groups' + ) + + #filter for group membership to samples + melted_filtered = melted.query('value != 0') + + #delete value {0,1} column-unnecessary since it now redundantly indicates membership + del melted_filtered['value'] + + #set Samples dtype as string + melted_filtered.loc[:,'Replicates'] = melted_filtered['Replicates'].astype(str) + + self.tidy_replicate_groups = melted_filtered + + def set_tidy_sample_groups(self): + """ + Setting tidy group membership of samples, where each sample is the observation and group membership is an attribute (column) + + Parameters + ---------- + None + + """ + + #copy sample groups dataframe + df = self.sample_groups.copy() + + #set Samples as column in dataframe + df.loc[:,'Samples'] = df.index + + #melt to tidy dataframe + melted = pd.melt(df, + id_vars=['Samples'], + value_vars=df.columns.tolist()[0:len(df.columns)-1], + var_name='Groups' + ) + + #filter for group membership to samples + melted_filtered = melted.query('value != 0') + + #delete value {0,1} column-unnecessary since it now redundantly indicates membership + del melted_filtered['value'] + + #set Samples dtype as string + melted_filtered.loc[:,'Samples'] = melted_filtered['Samples'].astype(str) + + self.tidy_sample_groups = melted_filtered + + def get_protein_annotations(self,string='hq'): + + ''' + Get Uniprot protein ontology data + + Parameters + ---------- + string : string + Indicate ontology data for either uniprot expert-curated or 'reviewed' proteins or all proteins from raw + + Output + ------- + tab : Ontology dataframe + ''' + + #get uniprot ontology + tab = get_uniprot_table() + + #subset ontology with proteins of interest + if string=='hq': + + inds = tab.index.isin(self.proteins) + + return tab[inds] + + if string=='all': + + return tab + + def get_uniprot_table(self): + """ + Upload uniprot database flat file + + Parameters + ---------- + None + + """ + + tab = pd.read_csv(self.data_dir+self.uniprot_file,delimiter="\t",index_col=0) + + return tab + + #ANALYSIS FUNCTIONS + + def manual_feature_extraction(self,df): + """ + Query protein quantification between reference and other groups + + Parameters + ---------- + df + dataframe to manually extract features + """ + + #load raw and sample group dataframes + df_samples = df + df_sample_groups = self.sample_groups + + #make rownames-presence/absence/mixed conditions of proteins amongst samples + val_grps = ('allq', 'allnotq', 'mixed') + tmp = list(it.product(val_grps,val_grps)) + rownames = [] + for i in tmp: + rownames.append("_".join(i)) + + #set column names-reference/indicator scenarios + x = self.groups != self.ref[0] + t = [ self.ref[0] + '/' + x for x in self.groups[x] ] + colnames = tuple(t) + + + #populate length and protein array dataframes + df_len = pd.DataFrame(index=rownames,columns=colnames) + df_arr = pd.DataFrame(index=rownames,columns=colnames) + + #populate each element with an empty array or list + for i, j in it.product(range(df_len.shape[0]),range(df_len.shape[1])): + df_len.iloc[i][j] = () + for i, j in it.product(range(df_arr.shape[0]),range(df_arr.shape[1])): + df_arr.iloc[i][j] = [] + + #make list of functions for assessing presence/absence/mixed protein status + singlefuncs = [ ( "allq", allq ) , + ("allnotq", allnotq ) , + ("mixed", mixed ) + ] + + #set reference group + ref_grp = self.ref[0] + + #loop through indicators to assess presense/absence/mixed proteins for each reference/indicator scenario and populate length/protein array dataframes + for i in self.groups[x]: + + #set reference/indicator scenario + gr1 = ref_grp + gr2 = i + colname = gr1+"/"+gr2 + print(colname) + + #make arrays of proteins for reference samples for each assessment condition + gr1_arr = [] + tmp = df_samples.T + arr1 = df_sample_groups.loc[gr1] == 1 + X = tmp[arr1.values].transpose() + for l in range(len(val_grps)): + tmp = singlefuncs[l][1](X)#slow + gr1_arr.append(tmp) + + #make arrays of proteins for reference samples for each assessment condition + gr2_arr = [] + tmp = df_samples.T + arr2 = df_sample_groups.loc[gr2] == 1 + X = tmp[arr2.values].transpose() + for k in range(len(val_grps)): + tmp = singlefuncs[k][1](X) + gr2_arr.append(tmp) + + #for each combination of gr1_arr and gr2_arr, do intersection and append to corresponding row in column of data frame. This gives proteins in each condition for each reference/indicator scenario + for m,n in it.product( range( len(gr1_arr) ) , range( len(gr2_arr) ) ): + rowname = singlefuncs[m][0]+"_"+singlefuncs[n][0] + df_len.loc[ rowname , colname ] = len ( np.intersect1d( gr1_arr[m], gr2_arr[n] ) ) + df_arr.loc[ rowname , colname ] = np.intersect1d( gr1_arr[m], gr2_arr[n] ) + + #dictionary of length and protein array dataframes + dictionary = { 'df_len' : df_len, 'df_arr' : df_arr} + + helper_dictionary = self.make_protein_substraction(dictionary) + + self.data['mfe'] = { 'main' : dictionary, 'helper' : helper_dictionary } + + def make_protein_substraction(self,dictionary=None): + ''' + Helper function only for manual_feature_extraction method to do set operations on protein results + + Right now supports difference of proteins + + Parameters + ---------- + dictionary + dictionary to fill in-fed from manual_feature_extraction + + Output + ------ + Dictionary of protein array length band array from difference ofv manually extracted features between ref and treat groups + ''' + #declare dictionary from manual feature extraction + mfe = dictionary + + #set comparisons made in mfe + comps_grps = mfe['df_len'].columns.tolist() + + #set protein feature comparisons from manual feature extraction + comps_prots = mfe['df_len'].index.tolist() + + #make combination of comparisons-resulting dataframe rows and columns + combs = list( + it.product( + comps_grps, + comps_grps + ) + ) + + #make dictionary of presence,absence, mixed. Values will be NxN dataframe labeled with combs above + protein_dict = dict.fromkeys( + comps_prots + ) + + #set dataframe to extract proteins from + df = mfe['df_arr'] + + #loop through dictionary keys which are the protein feature comparisons + for i in protein_dict.keys(): + + #make empty NxN dataframe to store protein lengths and arrays + empty_len = pd.DataFrame( + index = comps_grps, + columns = comps_grps + ) + + #make copied empty dataframe to store protein arrays + empty_diff = empty_len.copy() + + #loopp through dataframe index, columns and store length of difference and proteins from difference of sets + for j in comps_grps: + for k in comps_grps: + diff_arr = set(df.loc[i,j]) - set(df.loc[i,k]) + length = len(diff_arr) + empty_len.at[j,k] = length + empty_diff.at[j,k] = diff_arr + + #store dictionary of dataframes as value in dictionary + protein_dict[i] = { 'df_len' : empty_len, 'df_arr' : empty_diff } + + return protein_dict + + def hypothesis_testing(self,df,df_groups): + """ + Hypothesis testing of reference sample proteins versus treatment sample proteins. + + Parameters + ---------- + df + dataframe of values to test + df_groups + group membership of samples/replicates in df to test + + Outputs + ------- + df + hypothesis test results + """ + + #get subset dataframes by reference and treatment groups + df1 = self.get_sub_df(df,df_groups,self.ref[0]) + df2 = self.get_sub_df(df,df_groups,self.treat[0]) + + #List of hypothesis test names and functions + tests = self.tests + + #set dataframe to fill + df = pd.DataFrame(columns=['Protein','Test','Pvalue','Statistic']) + + #for each hypothesis test name and function + for i, hyp in enumerate(tests): + + #set test name + test = hyp[0] + + #for each protein + for j in range(0,df1.shape[0]): + + #get protein location in dataframes + firstloc = df1.iloc[j] + secondloc = df2.iloc[j] + + #make sure the arrays are filled with floats + a = firstloc.values.astype(float) + b = secondloc.values.astype(float) + + #make sure the name of the protein is the same in each dataframe + if firstloc.name == secondloc.name: + + #set protein name + protein = firstloc.name + else: + break + #set statistic from test + stat = hyp[1](a,b)[0] + + #set pvalue from test + pval = hyp[1](a,b)[1] + + #put data in pandas series + row = pd.Series([protein,test,pval,stat],index=df.columns) + + #add row to dataframe + df = df.append(row,ignore_index=True) + + #set correct object membership of dataframe columns + df = df.astype(dtype= { + "Protein":"str", + "Test":"str", + "Pvalue":"float64", + "Statistic":'float64' + } + ) + + return df + + def get_sub_df(self,df,df_groups,grp): + ''' + Helper function in class to get patient-subset dataframe. + + Subset larger dataframe by reference and treatment groups + + Used in hypothesis_testing() + + Parameters + ---------- + df + proteomics data dataframe given to hypothesis_testing + df_groups + groups dataframe given to hypothesis testing + grp str + group name for subsetting + + Output + ------ + subsetted dataset + ''' + + #get indices of replicates/samples in groups + inds = np.where(df_groups.loc[grp] == 1) + + #get + + return df.T.iloc[inds].T + + #PROTEIN SUBSET FUNCTIONS + + def proteins_with_uniprot_annot(self,df,status='reviewed'): + """ + Get proteins that have high annotation score by uniprot + + Parameters + ---------- + df + dataframe to subset + status {'reviewed','unreviewed'} + protein annotation score from uniprot curation + + Output + ------ + subsetted uniprot database + """ + + return self.uniprot_annot(df,status=status).index.ravel() + + def proteins_in_n_replicates_per_samples(self,df,n_reps=1): + """ + Subsetting dataset by proteins that are quantified in more atleast n replicates per sample for all samples + + Parameters + ---------- + df + dataframe to subset + n_reps + Least number of replicates quantified per sample + + Output + ------ + subsetted proteins + """ + samp_rep_dict = self.sample_replicate_dictionary + + atleast1_reps = [] + for samp in samp_rep_dict.keys(): + reps = samp_rep_dict[samp] + sub = df.T.loc[reps] + mask = sub.apply(lambda x : x > 0,axis=1) + #proteins quantified in more than 1 replicates of a sample + prot_bool = mask.sum(axis=0) > n_reps + [atleast1_reps.append(x) for x in prot_bool.index[prot_bool].tolist()] + + atleast1_rep_per_samp_prots = np.unique(atleast1_reps) + + return atleast1_rep_per_samp_prots + + def proteins_quant_all_reps(self,df): + """ + Helper function returning all proteins that + are quantified in every replicate. + + Parameters + ---------- + df + dataframe to subset + + Output + ------ + subsetted proteins + """ + + #determine how many reps show quantification of the protein + num_reps_quant = df.apply(lambda x : sum(x > 0),axis=1) + + #is the num reps all of them? + all_reps_quant = num_reps_quant.apply( + lambda x : x == df.shape[1]) + + #get protein names + allquant_prots = df.index[all_reps_quant] + + return allquant_prots + + def proteins_by_statistic_threshold(self, + df, + statistic='mean', + higher=False, + threshold=80): + """ + Proteins that meet a certain statistical threshold + e.g. proteins that have low variance across the dataset + + outputs proteins above/below that threshold + + e.g. threshold=25 gives proteins that are below the 25th quantile + of the statistical function. Threshold=80 gives proteins that are + below the 80th quantile of the statistical function + + Parameters + ---------- + df + dataframe to subset + statistic: {'mean','median', 'variance'} + statistic to apply across values + higher {True,False} + Indicates whether to subset by proteins with a high annotation score from Uniprot + threshold [0,100] + Quantile for statistic threshold + + Output + ------ + subsetted proteins + + """ + #possible statistical functions to threshold by + funcs = { + 'mean' : np.mean, + 'median' : np.median, + 'variance' : np.var, + 'std' : np.std + } + + #collect proteins in dataset + prots = df.index + + #create series by applying statistic + series = df.apply(funcs[statistic],axis=1) + + #store dataset value of threshold + thresh = (series.describe( + percentiles=np.arange(0,1,.01) + ) + .loc['0%':] + .iloc[threshold] + ) + + #determine direction of threshold + #if greater than 50, greater than or equal to, + #otherwise, less than + if higher: + return prots[series.where(series > thresh).notnull()] + else: + return prots[series.where(series <= thresh).notnull()] + + def proteins_by_intrasample_variability(self, + df,higher=False,threshold=80): + """ + Output proteins below a certain variance threshold for + replicates within all samples + + Parameters + ---------- + df + dataframe to subset + higher {True,False} + Indicates whether to subset by proteins with a high annotation score from Uniprot + threshold [0,100] + Quantile for statistic threshold + + Output + ------ + subsetted proteins + + """ + + #transpose + df = df.T + + samp_rep_dict = self.sample_replicate_dictionary + + prots = pd.Index([]) + + for samp in samp_rep_dict.keys(): + reps = samp_rep_dict.get(samp) + sub = df.loc[np.asarray(reps)] + prots = prots.append( \ + self.proteins_by_statistic_threshold(df=sub.T, + higher=False, + statistic='variance', + threshold=threshold)) + + return prots.unique() + + #HELPER FUNCTIONS + def uniprot_annot(self, df,status='reviewed'): + """ + Subset dataset by proteins that have high annotation score by uniprot + + Parameters + ---------- + df + dataframe to subset + annot_status {'reviewed','unreviewed'} + Annotation status in uniprot + + Output + ------ + subsetted dataset + """ + + #get uniprot data + annot = self.get_protein_annotations('hq') + + #get reviewed uniprot data + annot_reviewed = annot[annot['Status'].str.match(status)] + + #getting all uniprot reviewed proteins + cprots = annot_reviewed.iloc[:,0].index + + #filter raw for reviewed proteins + raw_reviewed = df[df.index.isin(cprots)] + + #set new protein column + tmp = raw_reviewed.assign(Proteins=raw_reviewed.index.values) + + #group proteins because there might be duplicates + grouped = tmp.groupby('Proteins') + + #get one of the duplicated proteins + reviewed = grouped.max() + + return reviewed + + def make_df_samples(self,df,agg='mean'): + """ + From df_replicates, make df_samples by applying to the replicates for a sample the estimator indicated in the helper function + + Parameters + ---------- + df + replicates dataframe to aggregate + agg: {'mean','median', 'variance'} + statistic to apply to replicate values for sample membership + + Output + ------ + subsetted dataset + """ + df_replicates = df + acc = df.index.tolist() + samples = self.samples + dictionary = self.sample_replicate_dictionary + + # initializing empty, desired dataframe of samples by proteins + df_samples = pd.DataFrame(columns=samples) + + #for each sample, apply the helper function to df_replicates sub dataframe to make df_samples + for sample in dictionary.keys(): + + #dataframe of replicates for a given sample + holder = df_replicates[dictionary[sample]] + + #determine sample protein value from replicate values + df = holder.agg(func=agg,axis=1) + + #put in df to larger df_samples + df_samples[sample] = df + + #add index-protein accessions + df_samples.index = acc + + return df_samples + + +if __name__=="__main__": + """ + Execute + """ + c = cohorts.Cohort('cumc') \ No newline at end of file diff --git a/cohorts/utils.py b/cohorts/utils.py new file mode 100644 index 0000000..662a880 --- /dev/null +++ b/cohorts/utils.py @@ -0,0 +1,248 @@ +import numpy as np +import pandas as pd +import seaborn as sns +import logging +from functools import reduce +import scipy.stats as sc + +def allq(X): + """ + Helper function used in manual_feature_extraction + + Parameters + ---------- + X + dataframe to subset + + Outputs + ------- + Subsetted dataframe with all proteins quantified + """ + applied = X.apply(lambda x: np.sum(x>0),axis=1) + bools = np.where(applied == len(X.columns)) + return X.iloc[bools].index.tolist() + +def allnotq(X): + """ + Helper function used in manual_feature_extraction + + Parameters + ---------- + X + dataframe to subset + + Outputs + ------- + Subsetted dataframe with no proteins quantified + """ + applied = X.apply(lambda x: np.sum(x),axis=1) + bools = np.where(applied == 0) + return X.iloc[bools].index.tolist() + +def mixed(X): + """ + Helper function used in manual_feature_extraction + + Parameters + ---------- + X + dataframe to subset + + Outputs + ------- + Subsetted dataframe with either 1 up to all proteins quantified + """ + applied = X.apply(lambda x: np.sum(x>0),axis=1) + condition1 = (applied < len(X.columns)) + condition2 = (applied > 0) + bools = np.where( condition1 & condition2 ) + return X.iloc[bools].index.tolist() + +def get_uniprot_table(file="/Users/npg2108/Research/Projects/exosome_pgf/data/uniprot-all_20171124.tab.gz"): + """ + Uploading uniprot database flat file + """ + tab = pd.read_csv(file,delimiter=" ",index_col=0) + + return tab + +def get_real(series, agg='mean'): + """ + Helper function to get array mean or return NaN for series of NaNs/floats. + Used to get sample value of protein for replicates in df_replicates + """ + + func = {'mean' : np.mean,'median': np.median,'variance' : np.var} + + # get logical list of whether the protein value is NaN + inds = [np.isnan(x) for x in series] + + #how many are NaN? + summ = np.sum(inds) + + #give NaN/float for protein value depending on number of NaNs in series + #returns NaN if all NaN values, and function value if atleasst one is non-NaN + if summ==len(inds): + return 0 + else: + #negativing-list of booleans for indices where non-NaN + reals = [not i for i in inds] + stat = func[agg](series[ reals ]) + return stat + +def rank_normalize(X): + """ + Helper function to normalize values in sample by normalized rank, so that protein values within a sample are [0,1] and indicate relative expression in that sample. Hopefully this will allow better comparisons between samples in a cohort. + """ + + df_ranked = X.apply(lambda x : sc.rankdata(x,method='dense')) + + df_ranked_normalized = df_ranked.apply(lambda x : (x / np.max(x))) + + return df_ranked_normalized + +def make_comparable(dfs,rank=True): + """ + Make list of cohort datasets (proteins x reps/samps) comparable i.e. make sure the + proteins are the same between the datasets and normalize. + """ + + #get list of sets of proteins in each cohort dataset + if type(dfs) == dict: + prot_set_lst = [set(x.index) for i,x in dfs.items()] + dfs = [x for i,x in dfs.items()] + else: + prot_set_lst = [set(x.index) for x in dfs] + + #get protein intersection + com_prots = multiple_set_intersection(*prot_set_lst) + + #iterate through dfs and normalize and append to new list + dfs_new = [] + for df in dfs: + if rank: + dfs_new.append(rank_normalize(df.loc[com_prots])) + else: + dfs_new.append(df.loc[com_prots]) + + return dfs_new + +def multiple_set_intersection(*sets): + """ + Return multiple set intersection. + from https://stackoverflow.com/questions/2541752/best-way-to-find-the-intersection-of-multiple-sets + """ + try: + return set.intersection(*sets) + except TypeError: # this is Python < 2.6 or no arguments + pass + + try: a_set= sets[0] + except IndexError: # no arguments + return set() # return empty set + + return reduce(a_set.intersection, sets[1:]) + +def quantileNormalize(df_input): + """ + From https://github.com/ShawnLYU/Quantile_Normalize/blob/master/quantile_norm.py + Quantile normalization method of a dataset + """ + df = df_input.copy() + #compute rank + dic = {} + for col in df: + dic.update({col : sorted(df[col])}) + sorted_df = pd.DataFrame(dic) + rank = sorted_df.mean(axis = 1).tolist() + #sort + for col in df: + t = np.searchsorted(np.sort(df[col]), df[col]) + df[col] = [rank[i] for i in t] + return df + + #from here +#https://gist.github.com/mpschr/5db20df78c034654f030 + +def multi_df_join(df_dict): + """ + Takes a list of dataframes with the same primary key (id) and merges the columns, using + the dictionary keys as suffixes in case there are conflicts with the column names. + Parameters + ---------- + df_dict: A dictionary where keys are strings (collision suffixes) and values are DataFrames + + Output + ------ + The merged data frames + """ + + # check if there are colliding column names + all_columns = [] + for df in df_dict.values(): + all_columns = all_columns + list(df.columns) + colliding_columns = set([x for x in all_columns if all_columns.count(x) > 1]) + + df = None + for suffix, input_df in df_dict.items(): + + # rename colliding columns + renamer_dict = {} + for col in list(input_df.columns): + if col in colliding_columns: + renamer_dict[col] = col + suffix + input_df.rename(columns=renamer_dict, inplace=True) + + # join columns + if df is None: + df = input_df + else: + df = df.join(input_df, how='outer') + logging.debug("Shape is currently: {}".format(df.shape)) + + return df + +def treat_ref_color_map(df,labels,groups,palette='hls'): + ''' + Create color dictionary for reference and treatment samples for use in plotting + + Parameters + ---------- + df + group labels from sample or replicate groups + labels + array of ref and treat group label + groups + label from dataframe in which we want to attribute colors to + Order by the labels + + Output + ------ + Samples to rgb pandas Series + ''' + + #create array of group names for correct sample membership + cond = [] * df.shape[0] + for g in groups: + for n in df.loc[g].ravel(): + if n == 1: + cond.append(g) + + #create a color palette with the same number of colors as unique groups-right now only 2 + network_pal = sns.color_palette(palette,n_colors=len(groups)) + + #create a dictionary where the key is the group and the values are the colors from the palette we just created + network_lut = dict(zip(groups, network_pal)) + + #convert array of group names to sample membership to a pandas series for mapping + networks = pd.Series(cond,index=labels) + + #map the colors to the series. Now we have a list of colors the same length as our dataframe, where unique values are mapped to the same color + network_colors = networks.map(network_lut) + + #change index class to string + network_colors.index = network_colors.index.astype('str') + + return network_colors + + diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..af2d57a --- /dev/null +++ b/setup.py @@ -0,0 +1,10 @@ +from setuptools import setup + +setup(name='cohorts', + version='0.1a', + description='Proteomics exosome_pgf cohort structure', + author='Tatonetti Lab', + author_email='npg2108@cumc.columbia.edu', + license='MIT', + packages=['cohorts'], + zip_safe=False) diff --git a/test.ipynb b/test.ipynb new file mode 100644 index 0000000..20e0715 --- /dev/null +++ b/test.ipynb @@ -0,0 +1,2040 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "nbpresent": { + "id": "24799cf3-8a2c-41b4-98c0-2861feeaa846" + } + }, + "outputs": [], + "source": [ + "import sys\n", + "import cohorts\n", + "import pandas as pd\n", + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Testing setters and attributes" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\tPatient cohort object for patient proteomics data.\n", + "\n", + "\tDataframes, variables, and functions facilitating the processing, analysis, and integration of the cohort data.\n", + "\n", + "\tParameters\n", + "\t----------\n", + "\tcohort: str\n", + "\t\tname of the patient cohort\n", + "\n", + "\tfile_dir: str\n", + "\t\tdirectory where replicate dataframe and \n", + "\t\tsample group membership dataframe file names are located\n", + "\n", + "\treplicates_file: str\n", + "\t\tname of the replicates dataframe file\n", + "\n", + "\t\tA proteins x B replicates\n", + "\t\ttab delimited\n", + "\n", + "\t\treplicate = \"SampleName\" + \"_Rep[0-9]\"\n", + "\n", + "\tsample_groups_file: str\n", + "\t\tname of the sample group file\n", + "\n", + "\t\tN groups x M samples\n", + "\n", + "\t\tsample = \"SampleName\"\n", + "\n", + "\tdata_dir: str\n", + "\t\tdirectory where extra data files are located\n", + "\t\t\n", + "\tuniprot_file: str\n", + "\t\tname of the uniprot database flat file located in data_dir\n", + "\n", + "\tExamples\n", + "\t--------\n", + "\t>>>c = cohorts.Cohort(cohort='cohort_name',\n", + "\t\tfile_dir=\"path/to/files/\"\n", + "\t\treplicates_file=\"file_name\",\n", + "\t\tsample_groups_file=\"sample_groups_file_name\",\n", + "\t\tdata_dir=\"path/to/data/dir/\",\n", + "\t\tuniprot_file=\"uniprot_flat_file\"\n", + "\t\t)\n", + "\t>>>c.set_replicates_hq()\n", + "\t>>>c.set_trans_replicates_hq()\n", + "\t>>>c.set_samples_hq()\n", + "\t>>>c.set_trans_samples_hq()\n", + "\n", + "\t\n" + ] + } + ], + "source": [ + "print(cohorts.Cohort.__doc__)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "nbpresent": { + "id": "7f9017a5-6455-4867-a8a2-c3842b3f9d9c" + }, + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/Users/npg2108/Research/Projects/exosome_pgf/cohorts\n", + "../data/\n", + "cumc\n", + "['53688_rep1', '53688_rep2', '53688_rep3', '53688_rep4', '54109_rep1', '54109_rep2', '54109_rep3', '54109_rep4', '54314_rep1', '54314_rep2', '54314_rep3', '54314_rep4', '54793_rep1', '54793_rep2', '54793_rep3', '54793_rep4', '55175_rep1', '55175_rep2', '55175_rep3', '55175_rep4', '56191_rep1', '56191_rep2', '56191_rep3', '56191_rep4', '56603_rep1', '56603_rep2', '56603_rep3', '56603_rep4', '56767_rep1', '56767_rep2', '56767_rep3', '56767_rep4', '62128_rep1', '62128_rep2', '62128_rep3', '62128_rep4', '53190_rep1', '53190_rep2', '53190_rep3', '53190_rep4', '53488_rep1', '53488_rep2', '53488_rep3', '53488_rep4', '56118_rep1', '56118_rep2', '56118_rep3', '56118_rep4', '57268_rep1', '57268_rep2', '57268_rep3', '57268_rep4', '57267_rep1', '57267_rep2', '57267_rep3', '57267_rep4', '57270_rep1', '57270_rep2', '57270_rep3', '57270_rep4', '57269_rep1', '57269_rep2', '57269_rep3', '57269_rep4']\n", + "{'53688': ['53688_rep1', '53688_rep2', '53688_rep3', '53688_rep4'], '54109': ['54109_rep1', '54109_rep2', '54109_rep3', '54109_rep4'], '54314': ['54314_rep1', '54314_rep2', '54314_rep3', '54314_rep4'], '54793': ['54793_rep1', '54793_rep2', '54793_rep3', '54793_rep4'], '55175': ['55175_rep1', '55175_rep2', '55175_rep3', '55175_rep4'], '56191': ['56191_rep1', '56191_rep2', '56191_rep3', '56191_rep4'], '56603': ['56603_rep1', '56603_rep2', '56603_rep3', '56603_rep4'], '56767': ['56767_rep1', '56767_rep2', '56767_rep3', '56767_rep4'], '62128': ['62128_rep1', '62128_rep2', '62128_rep3', '62128_rep4'], '53190': ['53190_rep1', '53190_rep2', '53190_rep3', '53190_rep4'], '53488': ['53488_rep1', '53488_rep2', '53488_rep3', '53488_rep4'], '56118': ['56118_rep1', '56118_rep2', '56118_rep3', '56118_rep4'], '57268': ['57268_rep1', '57268_rep2', '57268_rep3', '57268_rep4'], '57267': ['57267_rep1', '57267_rep2', '57267_rep3', '57267_rep4'], '57270': ['57270_rep1', '57270_rep2', '57270_rep3', '57270_rep4'], '57269': ['57269_rep1', '57269_rep2', '57269_rep3', '57269_rep4']}\n", + "['53688', '54109', '54314', '54793', '55175', '56191', '56603', '56767', '62128', '53190', '53488', '56118', '57268', '57267', '57270', '57269']\n", + "['NL' 'PGD' 'RV' 'LV' 'vasoplegia']\n", + "1204\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/anaconda/envs/cohorts_test/lib/python3.6/site-packages/pandas/core/indexing.py:621: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy\n", + " self.obj[item_labels[indexer[info_axis]]] = value\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
53688541095431454793551755619156603567676212853190534885611857268572675727057269
P619810.000000.000000.000000.000000.000000.000000.00000.000000.607000.309750.384000.843250.360501.255500.404000.25225
E7EX291.218001.009751.059501.472751.889751.457501.29001.416500.954000.864250.793500.831001.636251.129000.725752.06750
P621910.000000.000000.000000.000000.000000.000000.00000.000000.239000.135500.100500.184250.269750.346500.599000.09350
Q994601.077500.280000.283750.316500.000000.000000.00000.000000.307750.951000.349750.321250.000000.000000.000000.00000
P522090.850250.480750.603000.921751.055000.413750.59950.882750.763250.804500.814001.075750.996750.811750.558752.21100
\n", + "
" + ], + "text/plain": [ + " 53688 54109 54314 54793 55175 56191 56603 56767 \\\n", + "P61981 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.0000 0.00000 \n", + "E7EX29 1.21800 1.00975 1.05950 1.47275 1.88975 1.45750 1.2900 1.41650 \n", + "P62191 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.0000 0.00000 \n", + "Q99460 1.07750 0.28000 0.28375 0.31650 0.00000 0.00000 0.0000 0.00000 \n", + "P52209 0.85025 0.48075 0.60300 0.92175 1.05500 0.41375 0.5995 0.88275 \n", + "\n", + " 62128 53190 53488 56118 57268 57267 57270 57269 \n", + "P61981 0.60700 0.30975 0.38400 0.84325 0.36050 1.25550 0.40400 0.25225 \n", + "E7EX29 0.95400 0.86425 0.79350 0.83100 1.63625 1.12900 0.72575 2.06750 \n", + "P62191 0.23900 0.13550 0.10050 0.18425 0.26975 0.34650 0.59900 0.09350 \n", + "Q99460 0.30775 0.95100 0.34975 0.32125 0.00000 0.00000 0.00000 0.00000 \n", + "P52209 0.76325 0.80450 0.81400 1.07575 0.99675 0.81175 0.55875 2.21100 " + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
53688_rep153688_rep253688_rep353688_rep454109_rep154109_rep254109_rep354109_rep454314_rep154314_rep2...57267_rep357267_rep457270_rep157270_rep257270_rep357270_rep457269_rep157269_rep257269_rep357269_rep4
P61981NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN...NaNNaN0.7500.866NaNNaN0.4620.547NaNNaN
E7EX291.1421.3171.5560.8571.1501.0800.8041.0050.9301.235...1.5281.7310.7160.6260.7010.8601.6761.8571.5033.234
P62191NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN...NaNNaNNaN2.396NaNNaNNaN0.374NaNNaN
Q99460NaNNaN4.310NaNNaNNaN1.120NaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
P522091.2781.1600.3350.6280.4610.4060.7280.3280.7870.731...0.9211.1440.7380.6370.3320.5281.8052.4652.6131.961
\n", + "

5 rows × 64 columns

\n", + "
" + ], + "text/plain": [ + " 53688_rep1 53688_rep2 53688_rep3 53688_rep4 54109_rep1 \\\n", + "P61981 NaN NaN NaN NaN NaN \n", + "E7EX29 1.142 1.317 1.556 0.857 1.150 \n", + "P62191 NaN NaN NaN NaN NaN \n", + "Q99460 NaN NaN 4.310 NaN NaN \n", + "P52209 1.278 1.160 0.335 0.628 0.461 \n", + "\n", + " 54109_rep2 54109_rep3 54109_rep4 54314_rep1 54314_rep2 \\\n", + "P61981 NaN NaN NaN NaN NaN \n", + "E7EX29 1.080 0.804 1.005 0.930 1.235 \n", + "P62191 NaN NaN NaN NaN NaN \n", + "Q99460 NaN 1.120 NaN NaN NaN \n", + "P52209 0.406 0.728 0.328 0.787 0.731 \n", + "\n", + " ... 57267_rep3 57267_rep4 57270_rep1 57270_rep2 \\\n", + "P61981 ... NaN NaN 0.750 0.866 \n", + "E7EX29 ... 1.528 1.731 0.716 0.626 \n", + "P62191 ... NaN NaN NaN 2.396 \n", + "Q99460 ... NaN NaN NaN NaN \n", + "P52209 ... 0.921 1.144 0.738 0.637 \n", + "\n", + " 57270_rep3 57270_rep4 57269_rep1 57269_rep2 57269_rep3 57269_rep4 \n", + "P61981 NaN NaN 0.462 0.547 NaN NaN \n", + "E7EX29 0.701 0.860 1.676 1.857 1.503 3.234 \n", + "P62191 NaN NaN NaN 0.374 NaN NaN \n", + "Q99460 NaN NaN NaN NaN NaN NaN \n", + "P52209 0.332 0.528 1.805 2.465 2.613 1.961 \n", + "\n", + "[5 rows x 64 columns]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
53190_rep153190_rep253190_rep353190_rep453488_rep153488_rep253488_rep353488_rep453688_rep153688_rep2...57269_rep357269_rep457270_rep157270_rep257270_rep357270_rep462128_rep162128_rep262128_rep362128_rep4
NL0000000011...0000000000
PGD1111111100...1111111111
RV1111111100...1111111111
LV1111000000...1111111111
vasoplegia0000000000...0000000000
\n", + "

5 rows × 64 columns

\n", + "
" + ], + "text/plain": [ + " 53190_rep1 53190_rep2 53190_rep3 53190_rep4 53488_rep1 \\\n", + "NL 0 0 0 0 0 \n", + "PGD 1 1 1 1 1 \n", + "RV 1 1 1 1 1 \n", + "LV 1 1 1 1 0 \n", + "vasoplegia 0 0 0 0 0 \n", + "\n", + " 53488_rep2 53488_rep3 53488_rep4 53688_rep1 53688_rep2 \\\n", + "NL 0 0 0 1 1 \n", + "PGD 1 1 1 0 0 \n", + "RV 1 1 1 0 0 \n", + "LV 0 0 0 0 0 \n", + "vasoplegia 0 0 0 0 0 \n", + "\n", + " ... 57269_rep3 57269_rep4 57270_rep1 57270_rep2 \\\n", + "NL ... 0 0 0 0 \n", + "PGD ... 1 1 1 1 \n", + "RV ... 1 1 1 1 \n", + "LV ... 1 1 1 1 \n", + "vasoplegia ... 0 0 0 0 \n", + "\n", + " 57270_rep3 57270_rep4 62128_rep1 62128_rep2 62128_rep3 \\\n", + "NL 0 0 0 0 0 \n", + "PGD 1 1 1 1 1 \n", + "RV 1 1 1 1 1 \n", + "LV 1 1 1 1 1 \n", + "vasoplegia 0 0 0 0 0 \n", + "\n", + " 62128_rep4 \n", + "NL 0 \n", + "PGD 1 \n", + "RV 1 \n", + "LV 1 \n", + "vasoplegia 0 \n", + "\n", + "[5 rows x 64 columns]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
53688541095431454793551755619156603567676212853190534885611857268572675727057269
NL1111111100000000
PGD0000000011111111
RV0000000011111111
LV0000000011000011
vasoplegia0000000000010000
\n", + "
" + ], + "text/plain": [ + " 53688 54109 54314 54793 55175 56191 56603 56767 62128 \\\n", + "NL 1 1 1 1 1 1 1 1 0 \n", + "PGD 0 0 0 0 0 0 0 0 1 \n", + "RV 0 0 0 0 0 0 0 0 1 \n", + "LV 0 0 0 0 0 0 0 0 1 \n", + "vasoplegia 0 0 0 0 0 0 0 0 0 \n", + "\n", + " 53190 53488 56118 57268 57267 57270 57269 \n", + "NL 0 0 0 0 0 0 0 \n", + "PGD 1 1 1 1 1 1 1 \n", + "RV 1 1 1 1 1 1 1 \n", + "LV 1 0 0 0 0 1 1 \n", + "vasoplegia 0 0 1 0 0 0 0 " + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
SamplesGroups
0NL53688
5NL54109
10NL54314
15NL54793
20NL55175
\n", + "
" + ], + "text/plain": [ + " Samples Groups\n", + "0 NL 53688\n", + "5 NL 54109\n", + "10 NL 54314\n", + "15 NL 54793\n", + "20 NL 55175" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "top = \"~/Research/Projects/exosome_pgf/\"\n", + "file_dirs ={ 'cumc' : top+\"cumc/data/\", 'cedar' : top+\"cedarsinai/data/\", 'paris' : top+\"paris/data/\"}\n", + "replicates_files = { 'cumc' : \"df_replicates.tab\", 'cedar' : \"df_replicates.tab\", 'paris' : \"df_replicates.tab\"}\n", + "replicate_groups_files = { 'cumc' : \"df_replicate_groups.tab\", 'cedar' : \"df_replicate_groups.tab\", 'paris' : \"df_replicate_groups.tab\"}\n", + "sample_groups_files = { 'cumc' : \"df_sample_groups_v2.tab\", 'cedar' : \"df_sample_groups.tab\", 'paris' : \"df_sample_groups.tab\"}\n", + "cohort = 'cumc'\n", + "c = cohorts.Cohort(cohort=cohort,\n", + " data_dir=\"../data/\",file_dir=file_dirs[cohort],\n", + " replicates_file=replicates_files[cohort],\n", + " sample_groups_file=sample_groups_files[cohort],\n", + " uniprot_file=\"uniprot-all_20171124.tab.gz\")\n", + "print(c.cwd)\n", + "print(c.data_dir)\n", + "print(c.cohort)\n", + "print(c.replicates)\n", + "print(c.sample_replicate_dictionary) \n", + "print(c.samples)\n", + "print(c.groups)\n", + "print(len(c.proteins))\n", + "display(c.raw_samples.head())\n", + "display(c.raw_replicates.head())\n", + "display(c.replicate_groups.head())\n", + "display(c.sample_groups.head())\n", + "display(c.tidy_sample_groups.head())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## testing analysis functions" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "NL/PGD\n", + "NL/RV\n", + "NL/LV\n", + "NL/vasoplegia\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NL/PGDNL/RVNL/LVNL/vasoplegia
allq_allq535535535546
allq_allnotq63636369
allq_mixed1717170
allnotq_allq69696969
allnotq_allnotq76767676
allnotq_mixed0000
mixed_allq15151563
mixed_allnotq00035
mixed_mixed8383830
\n", + "
" + ], + "text/plain": [ + " NL/PGD NL/RV NL/LV NL/vasoplegia\n", + "allq_allq 535 535 535 546\n", + "allq_allnotq 63 63 63 69\n", + "allq_mixed 17 17 17 0\n", + "allnotq_allq 69 69 69 69\n", + "allnotq_allnotq 76 76 76 76\n", + "allnotq_mixed 0 0 0 0\n", + "mixed_allq 15 15 15 63\n", + "mixed_allnotq 0 0 0 35\n", + "mixed_mixed 83 83 83 0" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "c.set_ref('NL')\n", + "c.set_treat('PGD')\n", + "c.set_replicates_hq()\n", + "c.set_trans_replicates_hq()\n", + "c.set_samples_hq(uniprot_annot=True)\n", + "c.manual_feature_extraction(c.samples_hq)\n", + "display(c.data['mfe']['main']['df_len'])\n", + "#load raw and sample group dataframes" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NL/PGDNL/RVNL/LVNL/vasoplegia
NL/PGD0000
NL/RV0000
NL/LV0000
NL/vasoplegia1111110
\n", + "
" + ], + "text/plain": [ + " NL/PGD NL/RV NL/LV NL/vasoplegia\n", + "NL/PGD 0 0 0 0\n", + "NL/RV 0 0 0 0\n", + "NL/LV 0 0 0 0\n", + "NL/vasoplegia 11 11 11 0" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NL/PGDNL/RVNL/LVNL/vasoplegia
NL/PGD0000
NL/RV0000
NL/LV0000
NL/vasoplegia0000
\n", + "
" + ], + "text/plain": [ + " NL/PGD NL/RV NL/LV NL/vasoplegia\n", + "NL/PGD 0 0 0 0\n", + "NL/RV 0 0 0 0\n", + "NL/LV 0 0 0 0\n", + "NL/vasoplegia 0 0 0 0" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NL/PGDNL/RVNL/LVNL/vasoplegia
NL/PGD0000
NL/RV0000
NL/LV0000
NL/vasoplegia6660
\n", + "
" + ], + "text/plain": [ + " NL/PGD NL/RV NL/LV NL/vasoplegia\n", + "NL/PGD 0 0 0 0\n", + "NL/RV 0 0 0 0\n", + "NL/LV 0 0 0 0\n", + "NL/vasoplegia 6 6 6 0" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NL/PGDNL/RVNL/LVNL/vasoplegia
NL/PGD0000
NL/RV0000
NL/LV0000
NL/vasoplegia0000
\n", + "
" + ], + "text/plain": [ + " NL/PGD NL/RV NL/LV NL/vasoplegia\n", + "NL/PGD 0 0 0 0\n", + "NL/RV 0 0 0 0\n", + "NL/LV 0 0 0 0\n", + "NL/vasoplegia 0 0 0 0" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "display(c.data['mfe']['helper']['allq_allq']['df_len'])\n", + "display(c.data['mfe']['helper']['allnotq_allnotq']['df_len'])\n", + "display(c.data['mfe']['helper']['allq_allnotq']['df_len'])\n", + "display(c.data['mfe']['helper']['allnotq_allq']['df_len'])" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ProteinTestPvalueStatistic
0A0A075B6H9t-test0.1596261.485322
1A0A075B6I0t-test0.6413050.476162
2A0A075B6I1t-test0.315327-1.041432
3A0A075B6I4t-test0.0000515.744282
4A0A075B6I9t-test0.5059800.682629
5A0A075B6J1t-test0.6187970.508829
6A0A075B6J6t-test0.1947161.361986
7A0A075B6J9t-test0.9269960.093289
8A0A075B6K0t-test0.370359-0.925552
9A0A075B6K2t-test0.2957901.086082
10A0A075B6K4t-test0.144513-1.545552
11A0A075B6K5t-test0.292936-1.092785
12A0A075B6K6t-test0.101548-1.752511
13A0A075B6P5t-test0.3106751.051874
14A0A075B6Q5t-test0.916957-0.106166
15A0A075B6S4t-test0.5814290.564375
16A0A075B6S5t-test0.8900320.140803
17A0A075B6S6t-test0.1452871.542342
18A0A087WSX0t-test0.1386811.570236
19A0A087WSY4t-test0.6235040.501950
20A0A087WSY6t-test0.7707990.297038
21A0A087WSZ0t-test0.098795-1.768246
22A0A0A0MRZ9t-test0.215526-1.297221
23A0A0A0MS14t-test0.0042253.410355
24A0A0A0MT36t-test0.075822-1.917398
25A0A0B4J1U3t-test0.1619361.476540
26A0A0B4J1V0t-test0.7958920.263649
27A0A0B4J1V1t-test0.6353070.484812
28A0A0B4J1V2t-test0.1409851.560378
29A0A0B4J1V6t-test0.6917510.404787
...............
1686Q9UKW4Wilcoxon_RankSum_test0.1414821.470294
1687Q9UKY1Wilcoxon_RankSum_test1.0000000.000000
1688Q9UKY7Wilcoxon_RankSum_test0.000778-3.360672
1689Q9ULV4Wilcoxon_RankSum_test0.674424-0.420084
1690Q9UM47Wilcoxon_RankSum_test0.916359-0.105021
1691Q9UMZ2Wilcoxon_RankSum_test1.0000000.000000
1692Q9UN67Wilcoxon_RankSum_test0.833635-0.210042
1693Q9UNW1Wilcoxon_RankSum_test0.0928921.680336
1694Q9UQP3Wilcoxon_RankSum_test0.058707-1.890378
1695Q9Y289Wilcoxon_RankSum_test1.0000000.000000
1696Q9Y2H0Wilcoxon_RankSum_test0.000778-3.360672
1697Q9Y2W2Wilcoxon_RankSum_test1.0000000.000000
1698Q9Y345Wilcoxon_RankSum_test1.0000000.000000
1699Q9Y490Wilcoxon_RankSum_test0.344562-0.945189
1700Q9Y5C1Wilcoxon_RankSum_test0.0007783.360672
1701Q9Y5G5Wilcoxon_RankSum_test1.0000000.000000
1702Q9Y5G6Wilcoxon_RankSum_test1.0000000.000000
1703Q9Y5Q9Wilcoxon_RankSum_test0.400814-0.840168
1704Q9Y5S2Wilcoxon_RankSum_test0.008652-2.625525
1705Q9Y5Y7Wilcoxon_RankSum_test0.0117192.520504
1706Q9Y615Wilcoxon_RankSum_test0.8336350.210042
1707Q9Y6B7Wilcoxon_RankSum_test0.0007783.360672
1708Q9Y6D5Wilcoxon_RankSum_test0.4008140.840168
1709Q9Y6K1Wilcoxon_RankSum_test0.752714-0.315063
1710Q9Y6Q1Wilcoxon_RankSum_test1.0000000.000000
1711Q9Y6R7Wilcoxon_RankSum_test0.027423-2.205441
1712Q9Y6V0Wilcoxon_RankSum_test0.000778-3.360672
1713Q9Y6Y1Wilcoxon_RankSum_test1.0000000.000000
1714Q9Y6Y9Wilcoxon_RankSum_test0.7527140.315063
1715Q9Y6Z7Wilcoxon_RankSum_test0.2075781.260252
\n", + "

1716 rows × 4 columns

\n", + "
" + ], + "text/plain": [ + " Protein Test Pvalue Statistic\n", + "0 A0A075B6H9 t-test 0.159626 1.485322\n", + "1 A0A075B6I0 t-test 0.641305 0.476162\n", + "2 A0A075B6I1 t-test 0.315327 -1.041432\n", + "3 A0A075B6I4 t-test 0.000051 5.744282\n", + "4 A0A075B6I9 t-test 0.505980 0.682629\n", + "5 A0A075B6J1 t-test 0.618797 0.508829\n", + "6 A0A075B6J6 t-test 0.194716 1.361986\n", + "7 A0A075B6J9 t-test 0.926996 0.093289\n", + "8 A0A075B6K0 t-test 0.370359 -0.925552\n", + "9 A0A075B6K2 t-test 0.295790 1.086082\n", + "10 A0A075B6K4 t-test 0.144513 -1.545552\n", + "11 A0A075B6K5 t-test 0.292936 -1.092785\n", + "12 A0A075B6K6 t-test 0.101548 -1.752511\n", + "13 A0A075B6P5 t-test 0.310675 1.051874\n", + "14 A0A075B6Q5 t-test 0.916957 -0.106166\n", + "15 A0A075B6S4 t-test 0.581429 0.564375\n", + "16 A0A075B6S5 t-test 0.890032 0.140803\n", + "17 A0A075B6S6 t-test 0.145287 1.542342\n", + "18 A0A087WSX0 t-test 0.138681 1.570236\n", + "19 A0A087WSY4 t-test 0.623504 0.501950\n", + "20 A0A087WSY6 t-test 0.770799 0.297038\n", + "21 A0A087WSZ0 t-test 0.098795 -1.768246\n", + "22 A0A0A0MRZ9 t-test 0.215526 -1.297221\n", + "23 A0A0A0MS14 t-test 0.004225 3.410355\n", + "24 A0A0A0MT36 t-test 0.075822 -1.917398\n", + "25 A0A0B4J1U3 t-test 0.161936 1.476540\n", + "26 A0A0B4J1V0 t-test 0.795892 0.263649\n", + "27 A0A0B4J1V1 t-test 0.635307 0.484812\n", + "28 A0A0B4J1V2 t-test 0.140985 1.560378\n", + "29 A0A0B4J1V6 t-test 0.691751 0.404787\n", + "... ... ... ... ...\n", + "1686 Q9UKW4 Wilcoxon_RankSum_test 0.141482 1.470294\n", + "1687 Q9UKY1 Wilcoxon_RankSum_test 1.000000 0.000000\n", + "1688 Q9UKY7 Wilcoxon_RankSum_test 0.000778 -3.360672\n", + "1689 Q9ULV4 Wilcoxon_RankSum_test 0.674424 -0.420084\n", + "1690 Q9UM47 Wilcoxon_RankSum_test 0.916359 -0.105021\n", + "1691 Q9UMZ2 Wilcoxon_RankSum_test 1.000000 0.000000\n", + "1692 Q9UN67 Wilcoxon_RankSum_test 0.833635 -0.210042\n", + "1693 Q9UNW1 Wilcoxon_RankSum_test 0.092892 1.680336\n", + "1694 Q9UQP3 Wilcoxon_RankSum_test 0.058707 -1.890378\n", + "1695 Q9Y289 Wilcoxon_RankSum_test 1.000000 0.000000\n", + "1696 Q9Y2H0 Wilcoxon_RankSum_test 0.000778 -3.360672\n", + "1697 Q9Y2W2 Wilcoxon_RankSum_test 1.000000 0.000000\n", + "1698 Q9Y345 Wilcoxon_RankSum_test 1.000000 0.000000\n", + "1699 Q9Y490 Wilcoxon_RankSum_test 0.344562 -0.945189\n", + "1700 Q9Y5C1 Wilcoxon_RankSum_test 0.000778 3.360672\n", + "1701 Q9Y5G5 Wilcoxon_RankSum_test 1.000000 0.000000\n", + "1702 Q9Y5G6 Wilcoxon_RankSum_test 1.000000 0.000000\n", + "1703 Q9Y5Q9 Wilcoxon_RankSum_test 0.400814 -0.840168\n", + "1704 Q9Y5S2 Wilcoxon_RankSum_test 0.008652 -2.625525\n", + "1705 Q9Y5Y7 Wilcoxon_RankSum_test 0.011719 2.520504\n", + "1706 Q9Y615 Wilcoxon_RankSum_test 0.833635 0.210042\n", + "1707 Q9Y6B7 Wilcoxon_RankSum_test 0.000778 3.360672\n", + "1708 Q9Y6D5 Wilcoxon_RankSum_test 0.400814 0.840168\n", + "1709 Q9Y6K1 Wilcoxon_RankSum_test 0.752714 -0.315063\n", + "1710 Q9Y6Q1 Wilcoxon_RankSum_test 1.000000 0.000000\n", + "1711 Q9Y6R7 Wilcoxon_RankSum_test 0.027423 -2.205441\n", + "1712 Q9Y6V0 Wilcoxon_RankSum_test 0.000778 -3.360672\n", + "1713 Q9Y6Y1 Wilcoxon_RankSum_test 1.000000 0.000000\n", + "1714 Q9Y6Y9 Wilcoxon_RankSum_test 0.752714 0.315063\n", + "1715 Q9Y6Z7 Wilcoxon_RankSum_test 0.207578 1.260252\n", + "\n", + "[1716 rows x 4 columns]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ht = c.hypothesis_testing(df=c.samples_hq,df_groups=c.sample_groups)\n", + "ht" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## plotting with object data" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%matplotlib inline\n", + "import matplotlib.pylab as plt\n", + "import seaborn as sns\n", + "df_samples = c.raw_samples.apply(lambda x: np.log1p(x))\n", + "for n in range(0,15,1):\n", + " sns.distplot(df_samples.iloc[:,n],label=df_samples.index.values[n])\n", + "plt.xlabel('log1p of protein values')\n", + "plt.title('Sample distributions')\n", + "sns.despine()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "df_replicates = c.raw_replicates.fillna(0).apply(lambda x: np.log10(x+1))\n", + "for n in range(0,len(df_replicates.columns)-1,1):\n", + " sns.distplot(df_replicates.iloc[:,n],label=df_replicates.index.values[n])\n", + "plt.xlabel('log1p of protein values')\n", + "plt.title('Replicate distributions')\n", + "sns.despine()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python [conda env:cohorts_test]", + "language": "python", + "name": "conda-env-cohorts_test-py" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.4" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}