使用来自另一个 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 &lt;= 0 for slice warnings.warn("Degrees of freedom &lt;= 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 的有效方法是啥?

将列表转换为元组对[重复]

如何用来自另一个 DataFrame 的匹配 id 替换单词(在一个 DataFrame 中)?

如何在 Android 中使用适配器显示来自 Firebase 的组列表?