Как заменить некоторые цифры буквами в каждой строке файла (в соответствии с буквой, существующей в столбцах 5 и 6 этой строки)? - PullRequest
1 голос
/ 08 февраля 2012

У меня есть файл с пробелом, который выглядит следующим образом:

probeset_id submitted_id chr snp_pos alleleA alleleB 562_201 562_202 562_203 562_204 562_205 562_206 562_207 562_208 562_209 562_210 562_211 562_212 562_213 562_214 562_215 562_216 562_217 562_218 562_219 562_220 562_221 562_222 562_223 562_224 562_225 562_226 562_227 562_228 562_229 562_230 562_231 562_232 562_233 562_234 562_235 562_236 562_237 562_238 562_239 562_240 562_241 562_242 562_243 562_244 562_245 562_246 562_247 562_248 562_249 562_250 562_251 562_252 562_253 562_254 562_255 562_256 562_257 562_258 562_259 562_260 562_261 562_262 562_263 562_264 562_265 562_266 562_267 562_268 562_269 562_270 562_271 562_272 562_273 562_274 562_275 562_276 562_277 562_278 562_279 562_280 562_281 562_283 562_284 562_285 562_289 562_291 562_292 562_294 562_295 562_296 562_400 562_401 562_402 562_403 562_404 562_405 
AX-75448119 Chr1_41908741 1 41908741 T C 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 1 1 1 0 1 0 0 0 0 2 2 0 0 0 0 0 1 0 0 0 0 0 
AX-75448118 Chr1_41908545 1 41908545 T A 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 1 2 2 2 2 2 2 2 2 2 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 1 2 2 2 0 1 1 1 2 -1 1 2 0 0 2 1 1 0 1 0 1 2 1 0 0 1 2 2 1 2 2 0 1 2 2 2 2 2 2 0 1 0 0 0 1 2 2 2 2 0

Я хочу заменить цифры на буквы в соответствии со столбцами 5 и 6

  1. Заменить 0 на $5 $5 (два повторения столбца 5), например, если 5-й столбец - T, заменить 0 на T T
  2. Заменить 2 на $6 $6 (два повторения столбца 6), например, если в шестом столбце указано C, заменить 2 на C C
  3. Заменить 1 на $5 $6 например, если 5-й и 6-й столбцы равны T и C соответственно, заменить 1 на T C
  4. Заменить -1 на ? ?

Я должен отметить, что столбцы 5 и 6 могут быть T, A, C и G

Итак, что я хотел бы получить в качестве вывода:

AX-75448119 Chr1_41908741 1 41908741 T C T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T C T T T T T T T C T C T C T C T C T C T T T C T T T T T T T T C C C C T T T T T T T T T T T C T T T T T T T T T T 
AX-75448118 Chr1_41908545 1 41908545 T A A A A A A A A A A A A A A A A A A A T T T T T T T T T T T T T T T T T T T T T T T A A A A A A A A A A A A A A A A A A A T T T T T T T T T T T A T A T T T A T A T T T T T T T T T T T T T A A A A A A A T T T A T A T A A A ? ? T A A A T T T T A A T A T A T T T A T T T A A A T A T T T T T A A A A A T A A A A A T T T A A A A A A A A A A A A A T T T A T T T T T T T A A A A A A A A A T T

Я не знаю, возможно ли это по awk или нет! в противном случае я попробую в python, но я бы предпочел команду Linux, такую ​​как awk (которая намного быстрее, чем python, потому что я использую файл, содержащий 1,2 миллиона строк, и мой компьютер может поменяться местами на python!)

Ответы [ 5 ]

3 голосов
/ 08 февраля 2012
NR>1{
  o="1"; z="0"; t="2"
  if($5 == "T" && $6 == "C")
    o="T C"
  if($5 == "T")
    z="T T"
  if($6 == "C")
    t="C C"
  if($6 == "A")
    t="A A"
  for (i=7; i<=NF; i++) {
    gsub(/1/,o,$i)
    gsub(/0/,z,$i)
    gsub(/2/,t,$i)
    gsub(/-1/,"? ?", $i)
  }
}1

Вывод

$ awk -f allele.awk allele.in
probeset_id submitted_id chr snp_pos alleleA alleleB 562_201 562_202 562_203 562_204 562_205 562_206 562_207 562_208 562_209 562_210 562_211 562_212 562_213 562_214 562_215 562_216 562_217 562_218 562_219 562_220 562_221 562_222 562_223 562_224 562_225 562_226 562_227 562_228 562_229 562_230 562_231 562_232 562_233 562_234 562_235 562_236 562_237 562_238 562_239 562_240 562_241 562_242 562_243 562_244 562_245 562_246 562_247 562_248 562_249 562_250 562_251 562_252 562_253 562_254 562_255 562_256 562_257 562_258 562_259 562_260 562_261 562_262 562_263 562_264 562_265 562_266 562_267 562_268 562_269 562_270 562_271 562_272 562_273 562_274 562_275 562_276 562_277 562_278 562_279 562_280 562_281 562_283 562_284 562_285 562_289 562_291 562_292 562_294 562_295 562_296 562_400 562_401 562_402 562_403 562_404 562_405
AX-75448119 Chr1_41908741 1 41908741 T C T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T C T T T T T T T C T C T C T C T C T C T T T C T T T T T T T T C C C C T T T T T T T T T T T C T T T T T T T T T T
AX-75448118 Chr1_41908545 1 41908545 T A A A A A A A A A A A A A A A A A A A T T T T T T T T T T T T T T T T T T T T T T 1 A A A A A A A A A A A A A A A A A A T T T T T T T T T T 1 1 T T 1 1 T T T T T T T T T T T T 1 A A A A A A T T 1 1 1 A A ? ? 1 A A T T T T A A 1 1 T T 1 T T 1 A A 1 T T T T 1 A A A A 1 A A A A T T 1 A A A A A A A A A A A A T T 1 T T T T T T 1 A A A A A A A A T T

Примечание : Ваша спецификация все еще не завершена, вы никогда не говорите, что делать с 1, когда 5-й и 6-й столбцы не T C соответственно.Есть ряд перестановок, которые вы пропускаете.

2 голосов
/ 09 февраля 2012

Это может работать для вас:

awk 'NR>1{a=$3;$3="@";gsub(/ -1\>/," ? ?");gsub(/\<0\>/,$5 " " $5);gsub(/\<1\>/,$5 " " $6);gsub(/\<2\>/,$6 " " $6);$3=a;print}' file
2 голосов
/ 08 февраля 2012

awk определенно твой друг.

awk читает файл данных построчно. Вам не нужно / не нужно иметь какую-либо структуру цикла (если вы не очень продвинулись).

awk '{print $0}' inFile

Это все, что вам нужно, чтобы прочитать каждую строку файла и распечатать его (он попадет на ваш экран, поэтому не делайте большой файл)

обратите внимание, что я использовал $0 для обозначения «всей строки данных».

В Awk также есть переменные для ссылки на каждое поле данных, вы используете такие значения, как $2, чтобы напечатать второе поле в файле.

Я хочу заменить цифры на буквы в соответствии со столбцами 5 и 6. Итак, я хочу заменить 0 на TT (если 5-й столбец - T) и 2 на CC (если 6-й столбец - C) и 1 на TC (если 5-й и 6-й столбцы - T и C соответственно), и я хочу изменить -1 на? ? или же ! !

Итак, для вашей проблемы вы хотите проверить каждую строку, проверить определенные поля и установить новые значения.

awk 'NR>1{
  # replace 0 with T T (if the 5th column is T)
  if ($5 == 0) $5="TT"
  # and 2 by C C (if the 6th column is C)
  if ($6 == 2) $6="CC"
  # and 1 with T C (if the 5th and 6th columns are T and C respectively)
  if ($5 == "T" && $6 == "C") $1="1"
}'  inputFile  | sed 's/TT/T T/; s/CC/C C/'

Чтобы изменить все поля после определенного поля, включите этот код при необходимости,

awk 'NR>1{
  # replace 0 with T T (if the 5th column is T)
  if ($5 == 0) { 
     for (i=5; i<=NF;i++) {
         printf("T ")
     }
     printf("\n")
 }
 ......

} 'inputfile ...

NR>1 означает, что обрабатываются только номера строк больше 1.

Обратите внимание, что мы используем простую логику для улучшения ваших тестов. легко добавить еще и еще. Напомним, что много раз имеет смысл использовать «многоуровневую» логику if ($5==0) { ... } else if ($5 == 1) { ....}

Одна проблема - это, например, ваше требование вывести «C C». Когда вы делаете что-то вроде `$ 5 =" C C "в awk, awk перекалибрует номера полей, поэтому $ 5 будет C, а $ 6 будет C, а не значением, которое было там раньше.

Я взял короткий путь печати 'CC', а затем использовал sed в конце, чтобы создать значения 'C C', которые указывает ваша спецификация.

Я не уверен, что делать с

и я хочу изменить -1 на? ? или же ! !

так как это должно быть одно или другое, и я не уверен, с каким полем вы хотите работать. Используйте приведенный выше код в качестве руководства. Если вы застряли, опубликуйте новый вопрос с примерами входных данных, ожидаемым результатом, текущим результатом и используемым кодом.

Надеюсь, это поможет.

2 голосов
/ 08 февраля 2012

Это также будет делать замены в первых 4 столбцах, и я не стал беспокоиться о случае 1 или -1 (оставлен как упражнение для читателя), но вы сможете легко расширить это для соответствия:

$ perl -lape 's/0/$F[ 4 ] $F[ 4 ]/g; s/2/$F[ 5 ] $F[ 5 ]/g' input

Я действительно сомневаюсь, что awk будет быстрее, чем perl.

0 голосов
/ 09 февраля 2012

Лучше проверить значение поля по равенству, а не по регулярному выражению:

awk '
    NR==1 {print; next}
    {check0 = check1 = check2 = 0}
    $5 == "T"              {check0 = 1}
    $5 == "T" && $6 == "C" {check1 = 1}
    $6 == "C" || $6 == "A" {check2 = 1}
    {
        for (idx=7; idx <= NF; idx++)
            if      (check0 && $idx == 0) $idx = "T T"
            else if (check1 && $idx == 1) $idx = "T C"
            else if (check2 && $idx == 2) $idx = $6 " " $6
            else if ($idx == -1)          $idx = "? ?"
        print
    }
'
...