使用来自另一个 DataFrame 的组对一个 DataFrame 进行 T 测试
Posted
技术标签:
【中文标题】使用来自另一个 DataFrame 的组对一个 DataFrame 进行 T 测试【英文标题】:T-Test on one DataFrame with Groups from another DataFrame 【发布时间】:2016-05-09 20:19:08 【问题描述】:目标:
使用在另一个 DataFrame (df_cnv) 中找到的组对 DataFrame (df_rna) 执行 t 检验。减少测试 DataFrame (df_rna) t 检验中得分最高的行索引。
代码示例:
# Dataframe (df_cnv) that forms groups of columns (cells) either\ belonging to True or False for t-test.
cnv = 'gene': ['x','y','z','n'],
'cell_a': [0,-1,0,-1],
'cell_b': [0,-1,-1,-1],
'cell_c': [-1,0,-1,0],
'cell_d': [-1,0,-1,0],
'cell_e': [-1,0,0,0]
df_cnv = pd.DataFrame(cnv)
df_cnv.set_index('gene', inplace=True)
cnv_mask = df_cnv < 0
cnv_mask # True values are negative (gene loss is True)
# DataFrame for t-test and subsequent reduction to most significant rows
rna = 'gene': ['x','y','z','n'],
'cell_a': [1, 5, 8,9],
'cell_b': [8, 5, 4,9],
'cell_c': [8, 6, 1,1],
'cell_d': [1, 2, 7,1],
'cell_e': [5, 7, 9,1],
df_rna = pd.DataFrame(rna)
df_rna.set_index('gene')
# Manually computed T-Tests, save results in DataFrame df_report
x = scipy.stats.ttest_ind([8,1,5],[1,8])
y = scipy.stats.ttest_ind([5,5], [6,2,7])
z = scipy.stats.ttest_ind([4,1,7], [8,9])
n = scipy.stats.ttest_ind([9,9], [1,1,1])
tStat = [gene.statistic for gene in [x,y,z,n]]
pVal = [gene.pvalue for gene in [x,y,z,n]]
report = 'gene':['x','y','z','n'],
't_stat':tStat,
'p_val':pVal
df_report = pd.DataFrame(report)
df_report.set_index('gene', inplace=True)
# Create reduced version of test DataFrame (df_rna) to contain only rows (genes
df_pass = df_report.loc[df_report['p_val'] < 0.05]
passed_genes = set(df_pass.index)
passed_genes
df_rna_pass = df_rna.loc[df_rna['gene'].isin(passed_genes)]
df_rna_pass.set_index('gene')
问题:
对于我的大型数据集,手动设置 t 检验组是不可行的。当每行的单元格组为 True 和 False 时,如何计算整个 DataFrame df_rna
的所有 t 检验统计信息?
神秘挂起:(如果您没有缓存 rnadf_all[~cnv_mask]
的结果,就会发生这种情况)
C:\Users\test\Anaconda3\lib\site-packages\numpy\core\_methods.py:82: RuntimeWarning: Degrees of freedom <= 0 for slice
warnings.warn("Degrees of freedom <= 0 for slice", RuntimeWarning)
---------------------------------------------------------------------------
KeyboardInterrupt Traceback (most recent call last)
<ipython-input-16-ccabe33b2612> in <module>()
34
35 for r in rnadf_all[cnv_mask].iterrows():
---> 36 df_report.at[r[0], 't_stat'], df_report.at[r[0], 'p_val'] = scipy.stats.ttest_ind(r[1].dropna(), rnadf_all[~cnv_mask].loc[r[0]].dropna())
37
38 df_pass = df_report.loc[df_report['p_val'] < 0.05]
C:\Users\test\Anaconda3\lib\site-packages\pandas\core\frame.py in __getitem__(self, key)
1963 return self._getitem_array(key)
1964 elif isinstance(key, DataFrame):
-> 1965 return self._getitem_frame(key)
1966 elif is_mi_columns:
1967 return self._getitem_multilevel(key)
C:\Users\test\Anaconda3\lib\site-packages\pandas\core\frame.py in _getitem_frame(self, key)
2036 if key.values.dtype != np.bool_:
2037 raise ValueError('Must pass DataFrame with boolean values only')
-> 2038 return self.where(key)
2039
2040 def query(self, expr, **kwargs):
C:\Users\test\Anaconda3\lib\site-packages\pandas\core\generic.py in where(self, cond, other, inplace, axis, level, try_cast, raise_on_error)
3931 # try to align
3932 try_quick = True
-> 3933 if hasattr(other, 'align'):
3934
3935 # align with me
KeyboardInterrupt:
【问题讨论】:
【参考方案1】: from scipy import stats
# Create empty DF for t-test results
df_report = pd.DataFrame(index=df_rna.index, columns=['p_val', 't_stat'])
not_df_rna = df_rna[~cnv_mask]
# Iterate through df_rna rows, apply mask, drop NaN values, run ttest_ind and save result to df_report
for r in df_rna[cnv_mask].iterrows():
df_report.at[r[0], 't_stat'], df_report.at[r[0], 'p_val'] = stats.ttest_ind(r[1].dropna(), not_df_rna.loc[r[0]].dropna())
结果:
df_report
p_val t_stat
gene
x 0.966863 0.0450988
y 1 0
z 0.141358 -1.98508
n 0 inf
【讨论】:
此解决方案挂起,并引发警告C:\Users\test\Anaconda3\lib\site-packages\numpy\core\_methods.py:82: RuntimeWarning: Degrees of freedom <= 0 for slice warnings.warn("Degrees of freedom <= 0 for slice", RuntimeWarning)
。我以前从未见过这个。这是一个麻木的问题吗?
我没有注意到您发布了 Traceback。你能检查一下,将 ~cnv_mask 应用到 rnadf_all: rnadf_all[~cnv_mask] 需要多少时间?使用大 DataFrame 我的解决方案不是最优的,因为这将在循环的每次迭代中完成。所以最好在循环之前执行一次并缓存结果: not_rnadf_all = rnadf_all[~cnv_mask];然后在循环中将 rnadf_all[~cnv_mask].loc[r[0]].dropna() 替换为 not_rnadf_all.loc[r[0]].dropna()
我在 15 小时前将每个示例(最优和次优)提交到我们学校的计算集群。最佳的一个在 00:02:01 CPU 时间完成(似乎是合理的结果),最大 vmem 为 5.174G。不太理想的那个似乎仍在运行......
次优解决方案以 15:09:03 CPU 时间结束,最大 vmem 为 5.112G。我将编辑您的解决方案以反映最佳版本。再次感谢。
当我看到您对 DF 中 20000 行的评论时,我应该想到这一点。对于带有样本数据的 5x4 矩阵来说,这不是问题,但是如果使用 cnv_mask 过滤整个 DF 需要例如 4.5 秒,那么对于 20000 行,我们将花费 15 个小时分别循环处理每一行。愚蠢的错误。【参考方案2】:
我会先转置两个 DF,然后为 t 检验结果设置一个新的 DF:
cnv_mask_t = cnv_mask.transpose()
df_rna_t = df_rna.transpose()
df_tres = pd.dataframe(index=df_rna.index, columns=['pval', 'stat'])
然后您可以遍历基因,这些基因现在是列,并过滤掩码包含 True 的值:
for gene in df_rna_t:
col_mask = cnv_mask_t[gene]
tres = scipy.stats.ttest_ind(df_rna_t[gene][col_mask], df_rna_t[gene][~col_mask])
df_tres.loc[gene] = [tres.pvalue, tres.statistic]
我想你可以从这里拿走它。
【讨论】:
P.S.我目前在手机上,所以我无法测试代码。如果您需要更多帮助,请告诉我,我一定会在使用计算机时进行调查。 非常干净非常清晰的python。转置是唯一的问题,因为我正在处理大约 3000 列乘 20,000 行的多个数据帧。不然很容易理解,但是[~col_mask]
中的波浪号有什么作用呢?
它否定布尔向量,允许选择掩码为假的所有单元格。
@Thomas Matthew,如果你想摆脱换位,请看我的回答。以上是关于使用来自另一个 DataFrame 的组对一个 DataFrame 进行 T 测试的主要内容,如果未能解决你的问题,请参考以下文章
使用来自另一个 Dataframe 的公共索引值来完成一个空的 DataFrame
在 Scala 中使用来自另一个没有数组列的 DataFrame 的数组类型列创建 Spark DataFrame 的有效方法是啥?