テーブルから複数の個別のCSVファイルを作成したいと思います。以下は例表です。
gene REF_S1_host REF_S1_FL S1_host1 S1_host2 S1_FL REF_S2_host REF_S2_FL S2_host1 S2_host2 S2_FL
gene1 1 0 0 0 0 0 0 0 0 0
gene2 1 1 1 1 0 0 0 0 0 0
gene3 0 1 0 0 1 0 0 0 0 0
gene4 1 0 0 0 0 1 0 0 0 0
gene5 0 0 0 0 0 1 0 1 0 0
gene6 1 0 0 0 0 0 0 0 1 1
gene7 0 1 0 0 0 0 0 0 0 1
CSV(または他のタブで区切られたファイル)を作成したいと思います。
「S1」を含む列ヘッダーの下に「1」を含むすべてのデータを抽出しますが、同じ遺伝子の場合、「S2」を含むすべてのヘッダーの値は「0」です。たとえば、
gene REF_S1_host REF_S1_FL S1_host1 S1_host2 S1_FL REF_S2_host REF_S2_FL S2_host1 S2_host2 S2_FL gene1 1 0 0 0 0 0 0 0 0 0 gene2 1 1 1 1 0 0 0 0 0 0 gene3 0 1 0 0 1 0 0 0 0 0
REFファイル(S1またはS2)から値が「1」の行のみを取得しますが、他のすべてのフィールド(「REF」を含まない行ヘッダーなど)に対しては、「0」の行のみを取得します。たとえば、
gene REF_S1_host REF_S1_FL S1_host1 S1_host2 S1_FL REF_S2_host REF_S2_FL S2_host1 S2_host2 S2_FL gene1 1 0 0 0 0 0 0 0 0 0 gene4 1 0 0 0 0 1 0 0 0 0
ここで、REF_S1*には「1」が含まれます。みんなその他(すなわち、REFではない)S1サンプルは「0」+みんなREF_S2*は「0」+ですが、他のS2サンプル(REFではありません)は「1」です。たとえば、
gene REF_S1_host REF_S1_FL S1_host1 S1_host2 S1_FL REF_S2_host REF_S2_FL S2_host1 S2_host2 S2_FL gene6 1 0 0 0 0 0 0 0 1 1 gene7 0 1 0 0 0 0 0 0 0 1
最後に、すべての*FLは「1」、すべての*ホストは「0」です。たとえば、
gene REF_S1_host REF_S1_FL S1_host1 S1_host2 S1_FL REF_S2_host REF_S2_FL S2_host1 S2_host2 S2_FL gene3 0 1 0 0 1 0 0 0 0 0 gene7 0 1 0 0 0 0 0 0 0 1
しかし、どうすればいいのかわかりません。どんな提案でも歓迎します。
答え1
私は仮定する
- (多少)示されているように、データはスペースで区切られます。
- テーブルには常に11個の列があります(ただし、行数に制限はないかもしれません)。
- セル値にはスペースは含まれません。 (特に1行(タイトル)と1列(遺伝子)を除くすべての項目は
0
ORです1
。)
にするのは簡単ですawk
。
-
...「S1」を含む列ヘッダーの下に「1」を含むすべてのデータがありますが、同じ遺伝子の場合、「S2」を含むすべてのヘッダーの値は「0」です。
つまり、
-
(2列は1 OR 3列は1 OR 4列は1 OR 5列は1 OR 6列は1)
AND
7列は0
AND
8列は0 AND 9列は0
AND 10列は0 AND 11列は0awk -v OFS=',' ' NR==1 { next } ($2==1 || $3==1 || $4==1 || $5==1 || $6==1) && $7==0 && $8==0 && $9==0 && $10==0 && $11==0 { $1=$1; print } '
OFS
「出力フィールドの区切り記号」。入力がタブ区切りまたはスペースで区切られている場合でも、データをカンマ区切りフィールドに書き込むように指示-v OFS=','
します。awk
- 最初の行(タイトル行)をスキップするように指示します
NR==1 { next }
。awk
ヘッダー行を印刷するにはに変更しますNR==1 { $1=$1; print; next }
。 - 次の2行は、上記のAND / ORロジックをエンコードします。
{ $1=$1; print }
条件が満たされたら、ラインを印刷します。この$1=$1
メソッドは、最初のフィールドを自分と同じに設定します。何も起こらないように聞こえるかもしれません。実際には、awk
新しい(カスタム)出力フィールド区切り文字(カンマで指定)を使用して行を強制的に書き換えることはトリックです。心が変わり、入力に示されているように行を正確に出力するには、-v OFS=','
およびを削除します$1=$1;
。
-
... REFファイル(S1またはS2)には「1」の値があり、他のすべてのフィールドには「0」の値のみを持つ行のみ...
awk -v OFS=',' ' NR==1 { next } ($2==1 || $3==1 || $7==1 || $8==1) && $4==0 && $5==0 && $6==0 && $9==0 && $10==0 && $11==0 { $1=$1; print } '
-
ここで、REF_S1*には「1」が含まれており、他のすべて(つまり非REF)S1サンプルは「0」、すべてのREF_S2 *は「0」ですが、他のすべてのS2サンプル(非REF)は「1」です。
awk -v OFS=',' ' NR==1 { next } ($2==1 || $3==1) && $4==0 && $5==0 && $6==0 && $7==0 && $8==0 && ($9==1 || $10==1 || $11==1) { $1=$1; print } '
-
...すべての*FLは「1」で、すべての*ホストは「0」です。
awk -v OFS=',' ' NR==1 { next } ($3==1 || $6==1 || $8==1 || $11==1) && $2==0 && $4==0 && $5==0 && $7==0 && $9==0 && $10==0 { $1=$1; print } '
答え2
この問題に対する解決策は、次を使用することです。真珠3つのステップに進んでください。
- 選択基準正規表現が与えられたら、基準を満たすフィールド番号をエクスポートするサブルーチンを作成します。
- 最初の行またはヘッダー行を読み取るときにサブルーチンを使用して、リストされた各条件のフィールドインデックスを生成します。
- 最後に、これらのさまざまな配列の助けを借りて、List :: MoreUtilsモジュールから取得した関数を使用してブール選択基準を実行します。
- 注:ワンホットモードでは、4つの状況が個別に実行されます。それ以外の場合、出力はインターリーブされます。
perl -MList::MoreUtils=any,all -lane '
BEGIN {
sub mkAry {
my $re = shift;
grep { $_ }
map { $h{$_} }
grep { /$re/ } keys %h
}
}
if ($. == 1) {
print;
@h{@F} = (0..$#F);
@S1 = mkAry qr/S1/;
@S2 = mkAry qr/S2/;
@REF = mkAry qr/REF/;
@notREF = mkAry qr/^(?!.*REF)/;
@REF_S1 = mkAry qr/REF_S1/;
@REF_S2 = mkAry qr/REF_S2/;
@notREF_S1 = mkAry qr/^(?!.*REF)(?=.*S1)/;
@notREF_S2 = mkAry qr/^(?!.*REF)(?=.*S2)/;
@FL = mkAry qr/FL/;
@host = mkAry qr/host/;
next;
}
##_1_:
print if
any { $_ == 1 } @F[@S1] and
all { $_ == 0 } @F[@S2]
;
##_2_:
print if
any { $_ == 1 } @F[@REF] and
all { $_ == 0 } @F[@notREF]
;
##_3_:
print if
any { $_ == 1 } @F[@REF_S1] and
all { $_ == 0 } @F[@notREF_S1] and
all { $_ == 0 } @F[@REF_S2] and
any { $_ == 1 } @F[@notREF_S2]
;
##_4_:
print if
any { $_ == 1 } @F[@FL] and
all { $_ == 0 } @F[@host]
;
' file | column -t