2017-02-21 14 views
3

データを処理しようとしましたが、私の問題の解決策が見つけられません。小文字が30%を超える行を削除する

>ram 
cacacacacacacacacatatacacatacacatacacacacacacacacacacacacaca 
cacacacacacacaca 
>pam 
GAATGTCAAAAAAAAAAAAAAAAActctctct 
>sam 
AATTGGCCAATTGGCAATTCCGGAATTCaattggccaattccggaattccaattccgg 

and many lines more.... 

私はすべての行と対応するヘッダをフィルタリングしたい(ヘッダーが>で始まる)は、配列文字列(これらは>で始まらない)が30以上のパーセントを含むている:私はのように見えるファイルを持っています小文字。シーケンス文字列は複数の行にまたがることができます。私は、入力ファイルを読み込み、その後のawk、grepを扱うためのsedのwhileループのいくつかの組み合わせを試してみましたが、何も良い結果はありませんでした

>pam 
GAATGTCAAAAAAAAAAAAAAAAActctctct 

だからコマンドの後のような出力が見えるはずですxyが。

+3

あなたは試行して失敗しましたか?あなたの努力を示してください。 – Inian

+0

また、 'bash'は計算にも浮動小数点の値も評価できないので、これには適しません。あなたは 'bash'タグを削除することができます – Inian

答えて

2

や印刷の必要性、汚い:

awk '{n=length(gensub(/[A-Z]/,"","g"));if(NF && n/length*100 < 30)print a $0;a=RT}' RS='>[a-z]+\n' file 
  1. RS='>[a-z]+\n'を - 「を含む行にレコードセパレータを設定します> 'および名前

  2. RTは - 前回RT値

  3. n=length(gensub(/[A-Z]/,"","g"));保存 - - この値は

  4. a=RTの上にRSにマッチしているものによって設定された下部ケースの長さを取得することは

  5. if(NF && n/length*100 < 30)print a $0;文字 - 私たちが持ってチェック値が小文字の場合は30未満です

+0

'gawk'のみですが、うまくいきました。多分説明を加えてください。 – dawg

+0

ありがとうございます。これはうまくいき、あなたの説明はとても素敵で、何が起こっているのかを理解するのに役立ちます。 – JFS31

4

レコードの区切り文字を ">"に設定して、各ヘッダーをシーケンス行とともに1つのレコードとして扱う方法があります。

入力が ">"で始まるため、最初の空のレコードが発生するため、計算はNR > 1(レコード番号が1より大きい値)で保護されます。

文字の数を数えるには、ヘッダーの後のすべての行の長さを追加します。小文字の数を数えるために、文字列を別の変数に保存し、gsubを使用してすべての小文字を何も置き換えないようにします。つまり、gsubが代入回数を返すからです。これは便利な方法ですそれら。

最後に、比率を確認して印刷するかどうかを確認します(印刷を行うときは最初の「>」を追加します)。

BEGIN { RS = ">" } 

NR > 1 { 
    total_cnt = 0 
    lower_cnt = 0 
    for (i=2; i<=NF; ++i) { 
     total_cnt += length($i) 
     s = $i 
     lower_cnt += gsub(/[a-z]/, "", s) 
    } 
    ratio = lower_cnt/total_cnt 
    if (ratio < 0.3) print ">"$0 
} 


$ awk -f seq.awk seq.txt 
>pam 
GAATGTCAAAAAAAAAAAAAAAAActctctct 
+0

カウントに見出しを含めますか? – ceving

+0

ラベルである '>'で始まる行は、シーケンス文字列の一部ではないため、考慮しないことに注意してください。 –

+0

いいえ、私はヘッダーの文字を見ていないし、比率を計算するときに数えません。 (そのため、forループはi = 2で始まります) – jas

1
awk '/^>/{b=B;gsub(/[A-]/,"",b); 
      if(length(b) < length(B) * 0.3) print H "\n" B 
      H=$0;B="";next} 

    {B=((B != "") ? B "\n" : "") $0} 

    END{ b=B;gsub(/[A-]/,"",b); 
      if(length(b) < length(B) * 0.3) print H "\n" B 
     }' YourFile 

迅速QND優れた機能スイート

+0

ありがとうございました。これは本当に素晴らしいと私はそこに起こっているgtにしようとします。 – JFS31

1

今日では私は使用しませんsedまたはawkは、2行を超えるものはもう使用しません。

#! /usr/bin/perl 
use strict;        # Force variable declaration. 
use warnings;        # Warn about dangerous language use. 

sub filter         # Declare a sub-routing, a function called `filter`. 
{ 
    my ($header, $body) = @_;    # Give the first two function arguments the names header and body. 
    my $lower = $body =~ tr/a-z//;   # Count the translation of the characters a-z to nothing. 
    print $header, $body, "\n"    # Print header, body and newline, 
    unless $lower/length ($body) > 0.3; # unless lower characters have more than 30%. 
} 

my ($header, $body);      # Declare two variables for header and body. 
while (<>) {        # Loop over all lines from stdin or a file given in the command line. 
    if (/^>/) {        # If the line starts with >, 
    filter ($header, $body)    # call filter with header and body, 
     if defined $header;     # if header is defined, which is not the case at the beginning of the file. 
    ($header, $body) = ($_, '');   # Assign the current line to header and an empty string to body. 
    } else { 
    chomp;         # Remove the newline at the end of the line. 
    $body .= $_;       # Append the line to body. 
    } 
} 
filter ($header, $body);     # Filter the last record. 
+0

あなたの答えをありがとうが、悲しいことに私はPerlで働いたことはありません。だからあなたのコードを本当に理解できません。そして、私がawkやsedのようにしたいと思えば私が理解して修正できる解決策は、私のニーズをより良く適合させます。 – JFS31

+0

@ JFS31いくつかのコメントを追加しました。たぶんそれは新しいことを学ぶ良い例です。 – ceving

+0

非常にいいですね。私は一見を持って、それから何かを得ることを試みる:) – JFS31

関連する問題