Python 将规范化从Pandas转换为AWK以提高性能

Python 将规范化从Pandas转换为AWK以提高性能,python,pandas,awk,Python,Pandas,Awk,我有一个单细胞RNA测序数据集,我想对其进行规范化,但是由于它的大小(>1000000个细胞,~23000个基因),使用Python和Pandas根本不够高效(即使在优化数据类型、分区数据和128GB的RAM时) 因此,我希望在AWK(或其他有用的方法)中运行此规范化步骤,跳过内存密集型方法。从概念上讲,数据集是一个TSV文件,其中基因作为行,细胞作为列。大小约为130GB,在1GB的子集上进行测试时,需要6GB内存。在整个数据集上运行规范化是不可行的,但是规范化(比如说100个分区)仍然是一种

我有一个单细胞RNA测序数据集,我想对其进行规范化,但是由于它的大小(>1000000个细胞,~23000个基因),使用Python和Pandas根本不够高效(即使在优化数据类型、分区数据和128GB的RAM时)

因此,我希望在AWK(或其他有用的方法)中运行此规范化步骤,跳过内存密集型方法。从概念上讲,数据集是一个TSV文件,其中基因作为行,细胞作为列。大小约为130GB,在1GB的子集上进行测试时,需要6GB内存。在整个数据集上运行规范化是不可行的,但是规范化(比如说100个分区)仍然是一种非常无效的方法

这是一个规范化应该如何进行的示例(带有示例数据),我已成功地将其应用于较小的子集:

# determine dtypes and downcast to reduce memory usage
tmp_count_data = pd.read_csv(file_path, sep="\t", index_col=0, nrows=100)
tmp_float_cols = [c for c in tmp_count_data if tmp_count_data[c].dtype == "float64"]
tmp_float32_cols = {c: np.float32 for c in tmp_float_cols}

count_data = pd.read_csv(file_path, sep="\t", index_col=0, engine="c", dtype=tmp_float32_cols)

>>> count_data
       c1   c2
-              
GeneA  0.0  0.0
GeneB  1.0  0.0
GeneC  6.0  3.0
GeneD  4.0  3.0


def normalize(df):
    # load dataframe values
    dge = df.values
    # calculate column sums
    col_sums = np.apply_along_axis(sum,0,dge)
    # divide cell value by column sum, multiply by 10000, add 1, apply natural logarithm
    mat_dge_norm = np.log( dge/[float(x) for x in col_sums] * 10000 + 1 ) 
    # add column and row names back to dataframe
    df_dge_norm = pd.DataFrame(mat_dge_norm,index=df.index,columns=df.columns)
    # return dataframe
    return df_dge_norm
标准化应如下所示:

  • 将C列中的单元格k除以C列的和
  • 把这个除以10000
  • 在此基础上添加1
  • 取结果的自然对数

使用
awk
执行此操作几乎很简单,不需要太多内存,但需要扫描文件两次

$ awk 'NR==FNR {c1+=$2; c2+=$3; next} 
               {print $1, log($2/(c1*1000)+1), log($3/(c2*1000)+1)}' file{,}

GeneA 0 0
GeneB 9.0905e-05 0
GeneC 0.000545306 0.000499875
GeneD 0.00036357 0.000499875
您也可以格式化数字,但不确定是否需要


如果时间安排不合理,您可以分割文件,计算块的总和,然后将它们相加,然后用总数分割块,同样,内存不是问题,而是可以并发运行的进程数,假设p个进程,您可以几乎成比例地减少时间

使用
awk
执行此操作几乎很简单,不需要太多内存,但需要扫描文件两次

$ awk 'NR==FNR {c1+=$2; c2+=$3; next} 
               {print $1, log($2/(c1*1000)+1), log($3/(c2*1000)+1)}' file{,}

GeneA 0 0
GeneB 9.0905e-05 0
GeneC 0.000545306 0.000499875
GeneD 0.00036357 0.000499875
您也可以格式化数字,但不确定是否需要


如果时间安排不合理,您可以分割文件,计算块的总和,然后将它们相加,然后用总数分割块,同样,内存不是问题,而是可以并发运行的进程数,假设p个进程,您可以几乎成比例地减少时间

如果是130GB,则可能是采用大数据方法(即Spark)的时候了,它应该可以跨多个节点处理此问题如果是130GB,则可能是采用大数据方法(即Spark)的时候了,它应该可以跨多个节点处理此问题