ご覧のとおり、タブで区切られたデータには約4,000行と10列のファイルがあります。
ファイルの2番目の列にはさまざまな組織が記録されます。
samples tissue_s tissue_e tissue_d tissue_category tissue_visa sex study tissue_f age
samples1 ear CNS ear CNS CNS male 1 ear 365
samples2 ear CNS ear CNS CNS male 1 ear 365
samples3 ear CNS ear CNS CNS male 1 ear 365
samples4 ear CNS ear CNS CNS male 1 ear 365
samples5 ear CNS ear CNS CNS male 1 ear 365
samples6 stomach CNS ear CNS CNS male 1 ear 365
samples7 stomach CNS ear CNS CNS male 1 ear 365
samples8 stomach CNS ear CNS CNS male 1 ear 365
samples9 stomach CNS ear CNS CNS male 1 ear 365
...
...
10回以上表示されるすべての組織情報を印刷できることを願っています。
しかし、このようにして中間ファイルを生成することは非効率的だと思います。もっと簡潔で効率的な方法がありますか?
cat file | awk '{print $2}' | awk '{a[$0]++}END{for(i in a){if(a[i] > 10){print i}}}' > tmp.txt
grep -wFf tmp.txt file.txt > resule.txt
答え1
1つの方法は、入力ファイルを2回処理することです。
awk -F'\t' -v frq=10 -v colId=2 '
NR==FNR{ count[$colId]++; next }
count[$colId] >frq
' infile infile
注:カスタムawk変数は、レコードを出力する必要があるターゲット列IDの要素の最小繰り返し頻度を設定および指定するためfrq
に使用されます。colId
別の方法は、入力ファイルを処理することです。一度そしてただ数行バッファリングipnutデータが次のように2番目のフィールドにソートされている場合:
awk -F'\t' -v frq=10 -v colId=2 '
function prnt() { if(c>frq) printf("%s", buf); buf=c="" }
prev!=$colId{ prnt() }
{ c++; prev=$colId; buf = buf $0 ORS }
END{ prnt() }' infile
2番目のフィールドでソートされていない場合は、まずソートしてからawkに渡します。
<infile sort -t$'\t' -k2,2 |
awk -F'\t' -v frq=10 -v colId=2 '
function prnt() { if(c>frq) printf("%s", buf); buf=c="" }
prev!=$colId{ prnt() }
{ c++; prev=$colId; buf = buf $0 ORS }
END{ prnt() }'
答え2
使用幸せ(以前のPerl_6)
~$ raku -e 'my %h; do for lines.skip() {%h.push: .words.[1] => .words}; \
for %h.kv -> $k,@v {(put $k; .put for @v) if @v.elems > 4};' file
Perlファミリーの言語であるRakuを試すことに興味があるかもしれません。 1つの利点は、他の言語の組み合わせを使用している同僚とデータを交換するための組み込みの高度なUnicodeサポートです。
上記はハッシュを宣言し(2番目の列)をキーに、(すべての列)を値として使用して%h
自動的にハッシュを切り取りますlines
(ヘッダ行をping)。skip
ハッシュには重複キーが存在できないため、2番目の列の各個々の組織の下に行が追加されます。すべての行が処理された後、ハッシュは配列内のスカラーキーと値に入力されます。印刷のみ(例:OPサンプル入力の4行以上)。push
.words.[1]
.words
%h
%h.kv
$k
@a
@v.elems > 4
入力例:
samples tissue_s tissue_e tissue_d tissue_category tissue_visa sex study tissue_f age
samples1 ear CNS ear CNS CNS male 1 ear 365
samples2 ear CNS ear CNS CNS male 1 ear 365
samples3 ear CNS ear CNS CNS male 1 ear 365
samples4 ear CNS ear CNS CNS male 1 ear 365
samples5 ear CNS ear CNS CNS male 1 ear 365
samples6 stomach CNS ear CNS CNS male 1 ear 365
samples7 stomach CNS ear CNS CNS male 1 ear 365
samples8 stomach CNS ear CNS CNS male 1 ear 365
samples9 stomach CNS ear CNS CNS male 1 ear 365
出力例(上記のコード):
ear
samples1 ear CNS ear CNS CNS male 1 ear 365
samples2 ear CNS ear CNS CNS male 1 ear 365
samples3 ear CNS ear CNS CNS male 1 ear 365
samples4 ear CNS ear CNS CNS male 1 ear 365
samples5 ear CNS ear CNS CNS male 1 ear 365
必要に応じて出力を調整するのは非常に簡単です。put $k;
別の「組織」ヘッダーが必要ない場合は、通話を中止してください。また、タブ区切りの行を再構成するように行@a
出力が変更されました。.join("\t").put for @v
\t
上記の回答では、各列項目にスペースがないと仮定しています。スペースを分割(または分割しない)する.words
のが良い考えだからです。\t
各列項目が空白で区切られた単一要素になることを保証できない場合は、代わり.split("\t")
に使用してください。これらを1つにまとめると(上記と同じ出力が提供されますが、今タブで区切られます):
~$ raku -e 'my \%h; do for lines.skip() {\%h.push: .split("\t").[1] => .split("\t")}; \
for \%h.kv -> $k,@v {($k.put; .join("\t").put for @v) if @v.elems > 4};' file