Преобразование нормализации из Pandas в AWK для повышения производительности - PullRequest
0 голосов
/ 06 мая 2019

У меня есть набор данных РНК-секвенирования с одной ячейкой, который я хочу нормализовать, однако из-за его размера (> 1 000 000 ячеек, ~ 23 000 генов) использование Python с Pandas просто недостаточно эффективно (даже при оптимизации типов данных, разделении данных на части) и 128 ГБ оперативной памяти в моем распоряжении).

Поэтому я хочу запустить этот шаг нормализации в AWK (или других методах, которые были бы полезны), пропуская подход с интенсивным использованием памяти Pandas. Концептуально набор данных представляет собой файл TSV с генами в виде строк и ячеек в виде столбцов. Размер составляет ~ 130 ГБ, при тестировании на подмножестве ~ 1 ГБ потребуется около 6 ГБ ОЗУ в Pandas. Невозможно выполнить нормализацию для всего набора данных, но нормализация, скажем, 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

Нормализация должна идти следующим образом:

  • разделить ячейку k в столбце C на сумму столбца C
  • разделите это на 10000
  • добавить 1 к этому
  • принять натуральный логарифм результата

1 Ответ

2 голосов
/ 06 мая 2019

делать это с 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-процессы, вы можете сократить время практически пропорционально.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...