Как разделить указанный столбец c с остальными столбцами - PullRequest
0 голосов
/ 23 января 2020

У меня есть такая матрица (имена первых столбцов, остальные значения, вкладка разделителя i):

name1 A1 B1 C1 D1
name2 A2 B2 C2 D2

Матрица может быть огромной (это означает около сотен строк и столбцов). Это одинакового размера. Я могу ожидать нулевые значения.

Мне нужен вывод, как это:

name1 A1 B1 C1 D1 A1/B1 A1/C1 A1/D1
name2 A2 B2 C2 D2 A2/B2 A2/C2 A2/D2

Эта комбинация сохранить в новый файл. А затем создайте другую комбинацию:

name1 A1 B1 C1 D1 B1/A1 B1/C1 B1/D1
name2 A2 B2 C2 D2 B2/A2 B2/C2 B2/D2

и т. Д. И т. Д. => Разделите каждый столбец с остальными столбцами в матрице и сохраните как TSV в новый файл. А также округлить до трех знаков после запятой.

Я могу сделать это вручную с помощью сценария:

awk '{OFS="\t"}{$6=$2/($3+0.001); $7=$2/($4+0.001); $8=$2/($5+0.001)}1' input_file.tsv

Причина, по которой я добавляю число 0,001, заключается в том, что деление на ноль невозможно. Я могу создать сценарий оболочки с wile l oop, но это занимает много времени.

Я был бы очень рад любой автоматизации этого процесса.

Ответы [ 2 ]

5 голосов
/ 23 января 2020

Не могли бы вы попробовать следующее. Также, увидев вашу попытку, я предполагаю, что ваш Input_file разделен пробелом, НЕ запятым, если есть какой-либо другой разделитель, кроме пробела, добавьте BEGIN{FS=","} (запятая в качестве примера) также в следующем коде. Благодаря @accdias добавив логи c для удаления управляющих символов M

awk '
{
   gsub(/\r/,"")
}
{
  nf=NF
  close(out_file)
  for(k=2;k<=nf;k++){
    out_file=""
    for(i=2;i<=nf;i++){
      if($i!=0){
         $(NF+1)=sprintf("%.03f",$k/$i)
      }
      else{
         $(NF+1)=sprintf("%s","NaN")
      }
    }
    out_file=k"field_out_file"
    print >> (out_file)
    NF=nf
  }
}'  Input_file

О чем заботится код:

  • Создает имена выходных файлов в соответствии с именем поля, например 2field_out_file означает, что 2-е поле делится на все элементы через файл Input_file /.
  • В фоновом режиме все выходные файлы будут открыты, так что close функция используется, чтобы избежать ошибок типа too many files opened.
  • . Она проверяет значение 0, если что-либо делится на ноль, выводит NaN в выводе.
1 голос
/ 23 января 2020

Поскольку вы пометили вопрос с помощью python-3.x, вот скрипт для достижения того, что вы хотите (хотя для этого требуется Python 3.6+ из-за f-strings):

from pathlib import Path
import csv

source = Path('input.tsv')

with source.open() as src:
    csvreader = csv.reader(src, dialect='excel-tab')

    # get number of columns and rewind
    cols = len(next(csvreader)[1:])
    src.seek(0)

    csvwriters = []

    # create a csv.writer for each column
    for i in range(cols):
        # output_col_01.tsv, output_col_02.tsv ...
        csvwriters.append(
            csv.writer(
                Path(f'output_col_{i + 1:02d}.tsv').open('w'),
                dialect='excel-tab'
            )
        )

    nan = float('nan')

    for name, *cols in csvreader:
        for i, a in enumerate(cols):
            row = [name]
            for j, b in enumerate(cols):
                # skip the quotient of a col by itself
                if i != j:
                    a = float(a)
                    b = float(b)
                    # nan if division by zero
                    row.append(round(a / b, 4) if b else nan)

            csvwriters[i].writerow(row)

вместо добавив 0.001 для операций, в которых делитель равен 0, я решил вернуть float('nan').

. Он не будет делить столбец сам по себе и округлять частные до 4 десятичных знаков.

Наконец, если вы используете Python версию более раннюю, чем 3.6 (но вам все равно понадобится Python версия 3.4+ из-за pathlib.Path()), тогда замените следующую строку:

Path(f'output_col_{i + 1:02d}.tsv').open('w'),

с:

Path('output_col_%02d.tsv' % (i + 1)).open('w'),

Это необходимо, потому что f-strings были введены в Python 3.6.

...