PineBioML 1.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,201 @@
1
+ import numpy as np
2
+ import pandas as pd
3
+ import matplotlib.pyplot as plt
4
+ from scipy.stats import t
5
+ from . import SelectionPipeline
6
+
7
+
8
+ class Volcano_selection(SelectionPipeline):
9
+ """
10
+ volcano plot.
11
+
12
+ """
13
+
14
+ def __init__(self,
15
+ k,
16
+ strategy="fold",
17
+ p_threshold=0.05,
18
+ fc_threshold=2,
19
+ log_domain=False,
20
+ absolute=True):
21
+ """
22
+
23
+ Args:
24
+ strategy (str, optional): Choosing strategy. One of {"p" or "fold"} Defaults to "fold".
25
+ p_threshold (float, optional): p-value threshold. Only feature has p-value higher than threshold will be considered. Defaults to 0.05.
26
+ fc_threshold (int, optional): fold change threshold. Only feature has fold change higher than threshold will be considered. Defaults to 2.
27
+ log_domain (bool, optional): Whether input data is in log_domain. Defaults to False.
28
+ absolute (bool, optional): If true, then take absolute value on score while strategy == "p". Defaults to True.
29
+ """
30
+ super().__init__(k=k)
31
+ self.strategy = strategy
32
+ self.fc_threshold = fc_threshold
33
+ self.p_threshold = p_threshold
34
+ self.log_domain = log_domain
35
+ self.absolute = absolute
36
+ self.name = "Volcano Plot_" + self.strategy
37
+ self.missing_value = 0
38
+
39
+ def Scoring(self, x, y):
40
+ """
41
+ Compute the fold change and p-value on each feature.
42
+
43
+ Args:
44
+ x (pandas.DataFrame or a 2D array): The data to extract information.
45
+ y (pandas.Series or a 1D array): The target label for methods. Defaults to None.
46
+
47
+ Returns:
48
+ pandas.DataFrame: A dataframe records p-value and fold change.
49
+ """
50
+ positive = y == 1
51
+ negative = y == 0
52
+
53
+ x = x.replace(0, np.nan)
54
+
55
+ # fold change
56
+ if not self.log_domain:
57
+ log_fold = np.log2(x[positive].mean(axis=0) /
58
+ x[negative].mean(axis=0))
59
+ else:
60
+ log_fold = x[positive].mean(axis=0) - x[negative].mean(axis=0)
61
+
62
+ # Welch t test:
63
+ # normal assumption
64
+ # diffirent sample size
65
+ # diffirent varience
66
+ # unpaired
67
+ n_positive = x[positive].shape[0]
68
+ n_negative = x[negative].shape[0]
69
+ diff = x[positive].mean(axis=0) - x[negative].mean(axis=0)
70
+
71
+ s_positive = ((x[positive] - x[positive].mean(axis=0))**
72
+ 2).sum(axis=0) / (n_positive - 1)
73
+ s_negative = ((x[negative] - x[negative].mean(axis=0))**
74
+ 2).sum(axis=0) / (n_negative - 1)
75
+ st = np.sqrt(s_positive / n_positive + s_negative / n_negative)
76
+
77
+ t_statistic = np.abs(diff / st)
78
+ df = (s_positive / n_positive + s_negative / n_negative)**2 / (
79
+ (s_positive / n_positive)**2 / (n_positive - 1) +
80
+ (s_negative / n_negative)**2 / (n_negative - 1))
81
+
82
+ # 2 side testing
83
+ #print("t statistic: ", t_statistic.min(), t_statistic.mean(), t_statistic.max())
84
+ #print("degree of freedom: ", df.min(), df.mean(), df.max())
85
+
86
+ p_value = t.cdf(x=-t_statistic, df=df) * 2
87
+ log_p = -np.log10(p_value)
88
+
89
+ self.scores = pd.DataFrame(
90
+ {
91
+ "log_p_value": log_p,
92
+ "log_fold_change": log_fold
93
+ },
94
+ index=log_fold.index)
95
+ return self.scores.copy()
96
+
97
+ def Choose(self, scores):
98
+ """
99
+ Choosing the features which has score higher than threshold in assigned strategy.
100
+
101
+ If strategy == "fold": sort in fold change and return p-value
102
+
103
+ If strategy == "p": sort in p-value and return fold change
104
+
105
+ Args:
106
+ scores (pandas.DataFrame): A dataframe records p-value and fold change.
107
+ k (int): Number of features to select.
108
+
109
+ Returns:
110
+ pandas.Series: The score for k selected features in assigned strategy.
111
+ """
112
+ log_fold = scores["log_fold_change"]
113
+ log_p = scores["log_p_value"]
114
+ # choose fold change > 2 and p value < 0.05 in log scale
115
+ significant = np.logical_and(
116
+ np.abs(log_fold) >= np.log2(self.fc_threshold), log_p
117
+ > -np.log10(self.p_threshold))
118
+ self.significant = significant
119
+
120
+ # choose top k logged p-value
121
+ if self.strategy == "fold":
122
+ selected = np.abs(log_fold).loc[significant].sort_values().tail(
123
+ self.k)
124
+ selected_score = pd.Series(log_p.loc[selected.index],
125
+ index=selected.index,
126
+ name=self.name)
127
+ elif self.strategy == "p":
128
+ selected = log_p.loc[significant].sort_values().tail(self.k)
129
+ if self.absolute:
130
+ selected_score = pd.Series(
131
+ np.abs(log_fold.loc[selected.index]),
132
+ index=selected.index,
133
+ name=self.name).sort_values(ascending=False)
134
+ else:
135
+ selected_score = pd.Series(
136
+ log_fold.loc[selected.index],
137
+ index=selected.index,
138
+ name=self.name).sort_values(ascending=False)
139
+ else:
140
+ raise "select_by must be one of {fold} or {p}"
141
+
142
+ # volcano plot importance
143
+ self.selected_score = selected_score
144
+ return self.selected_score.copy()
145
+
146
+ def plotting(self,
147
+ external=False,
148
+ external_score=None,
149
+ title="Welch t-test volcano",
150
+ show=True,
151
+ saving=False,
152
+ save_path="./output/"):
153
+ """
154
+ Plotting
155
+
156
+ Args:
157
+ external (bool, optional): True to use external score. Defaults to False.
158
+ external_score (_type_, optional): External score to be used. Only activate when external == True. Defaults to None.
159
+ title (str, optional): plot title. Defaults to "Welch t-test volcano".
160
+ show (bool, optional): True to show the plot. Defaults to True.
161
+ saving (bool, optional): True to save the plot. Defaults to False.
162
+ save_path (str, optional): The path to save plot. Only activate when saving == True. Defaults to "./output/images/".
163
+ """
164
+ log_fold = self.scores["log_fold_change"]
165
+ log_p = self.scores["log_p_value"]
166
+ # choose fold change > 2 and p value < 0.05 in log scale
167
+ significant = np.logical_and(
168
+ np.abs(log_fold) >= np.log2(self.fc_threshold), log_p
169
+ > -np.log10(self.p_threshold))
170
+
171
+ if external:
172
+ selected = pd.Series(False, index=self.scores.index)
173
+ selected.loc[external_score.index] = True
174
+ else:
175
+ selected = pd.Series(False, index=significant.index)
176
+ selected.loc[self.selected_score.index] = True
177
+
178
+ # silent
179
+ plt.scatter(x=log_fold[~significant],
180
+ y=log_p[~significant],
181
+ s=0.5,
182
+ color='gray')
183
+ # not selected
184
+ plt.scatter(x=log_fold[significant][~selected],
185
+ y=log_p[significant][~selected],
186
+ s=2)
187
+ # selected
188
+ if external:
189
+ plt.scatter(x=log_fold[selected], y=log_p[selected], s=2)
190
+ else:
191
+ plt.scatter(x=log_fold[selected], y=log_p[selected], s=2)
192
+
193
+ plt.title(title)
194
+ plt.xlabel("log_2 fold")
195
+ plt.axvline(1, linestyle="dotted", color="gray")
196
+ plt.axvline(-1, linestyle="dotted", color="gray")
197
+ plt.axhline(-np.log10(0.05), linestyle="dotted", color="gray")
198
+ plt.ylabel("log_10 p")
199
+ if saving:
200
+ plt.savefig(save_path + title, format="png")
201
+ plt.show()
@@ -0,0 +1,145 @@
1
+ import matplotlib.pyplot as plt
2
+
3
+ import warnings
4
+ from sklearn.exceptions import ConvergenceWarning
5
+
6
+ # Suppress only ConvergenceWarning
7
+ warnings.filterwarnings("ignore", category=ConvergenceWarning)
8
+
9
+
10
+ class SelectionPipeline:
11
+ """
12
+ The basic pipeline for selection methods. It includes 2 parts: Scoring and Choosing.
13
+ The detail methods is to be determinded.
14
+
15
+ """
16
+
17
+ def __init__(self, k=None):
18
+ """
19
+ Initialize the selection pipeline.
20
+
21
+ Args:
22
+ k (int or None): select top k important feature. k = -1 means selecting all, k = None means selecting the feature that have standarized score > 1. Default = None
23
+ """
24
+ self.k = k
25
+ self.name = "base"
26
+ self.scores = None
27
+ self.selected_score = None
28
+
29
+ def Scoring(self, x, y=None):
30
+ """
31
+ The method to scores features is to be implemented.
32
+
33
+ Args:
34
+ x (pandas.DataFrame or a 2D array): The data to extract information.
35
+ y (pandas.Series or a 1D array): The target label for methods. Defaults to None.
36
+
37
+ Returns:
38
+ pandas.Series or pandas.DataFrame: The score for each feature. Some elements may be empty.
39
+ """
40
+ self.scores = x.max().sort_values(ascending=False) # top is better
41
+ return self.scores.copy()
42
+
43
+ def Choose(self, scores):
44
+ """
45
+ Choosing features according to scores.
46
+
47
+ Args:
48
+ scores (pandas.Series or pandas.DataFrame): The score for each feature. Some elements may be empty.
49
+ k (int): Number of feature to select. The result may less than k
50
+
51
+ Returns:
52
+ pandas.Series or pandas.DataFrame: The score for k selected features. May less than k.
53
+ """
54
+ self.selected_score = scores.head(self.k)
55
+ self.selected_score = self.selected_score[self.selected_score != 0]
56
+
57
+ return self.selected_score.copy()
58
+
59
+ def Select(self, x, y):
60
+ """
61
+ A functional stack of: Scoring -> Choosing
62
+ if k == None, choose k such that:
63
+ z-scores = (scores - scores.mean())/scores.std()
64
+ k = # (z-scores > 1)
65
+
66
+
67
+ Args:
68
+ x (pandas.DataFrame or a 2D array): The data to extract information.
69
+ y (pandas.Series or a 1D array): The target label for methods.
70
+ k (int): Number of feature to select. The result may less than k.
71
+
72
+ Returns:
73
+ pandas.Series: The score for k selected features. May less than k.
74
+ """
75
+ # x should be a pd dataframe or a numpy array without missing value
76
+ scores = self.Scoring(x, y)
77
+ if self.k:
78
+ # k not None
79
+ selected_score = self.Choose(scores)
80
+ else:
81
+ # k is None
82
+ z_scores = (scores - scores.mean()) / (scores.std() + 1e-4)
83
+ selected_score = scores[z_scores > 1.]
84
+
85
+ return selected_score
86
+
87
+ def fit(self, x, y):
88
+ """
89
+ sklearn api
90
+
91
+ Args:
92
+ x (pandas.DataFrame or a 2D array): The data to extract information.
93
+ y (pandas.Series or a 1D array): The target label for methods.
94
+ """
95
+ self.Select(x, y)
96
+ return self
97
+
98
+ def transform(self, x):
99
+ return x[self.selected_score.index]
100
+
101
+ def fit_transform(self, x, y):
102
+ self.fit(x, y)
103
+ return self.transform(x)
104
+
105
+ def what_matters(self):
106
+ return self.selected_score
107
+
108
+ def Plotting(self):
109
+ """
110
+ plot hist graph of selectied feature importance
111
+ """
112
+ fig, ax = plt.subplots(1, 1)
113
+ ax.bar(self.selected_score.index, self.selected_score)
114
+ for label in ax.get_xticklabels(which='major'):
115
+ label.set(rotation=45, horizontalalignment='right')
116
+ ax.set_title(self.name + " score")
117
+
118
+ plt.show()
119
+
120
+ def reference(self) -> dict[str, str]:
121
+ """
122
+ This function will return reference of this method in python dict.
123
+ If you want to access it in PineBioML api document, then click on the >Expand source code
124
+
125
+ Returns:
126
+ dict[str, str]: a dict of reference.
127
+ """
128
+ refers = {
129
+ "sklearn publication":
130
+ "https://dl.acm.org/doi/10.5555/1953048.2078195"
131
+ }
132
+
133
+ return refers
134
+
135
+ def Diagnose(self):
136
+ """
137
+ Give diagnose of selection.
138
+ """
139
+ #pass
140
+
141
+ def Report(self):
142
+ """
143
+ Give diagnose of selection.
144
+ """
145
+ #pass