ダウンストリームプログラムで処理する大きな(〜900MB)タブ区切りテキストファイルがあります。欠損値のある行を削除する必要があります。正しい列数が各行にあります(したがって、欠損値は2つのタブに対応します)。
注:実際のデータは約200万行、80〜300列です。使用できる文字は、az AZ 0-9-(ハイフン)_(アンダースコア)およびタブ(区切り記号)です。スペースまたは特殊文字は、ファイル
この種のスクリプトは初めてなので、提供されたコードの説明をいただければ幸いです。私は通常Rを使用しますが、ファイルサイズがRのデータ操作機能を超えています
ターミナルで(またはシェルスクリプト内で)ファイルから欠損値のある行を削除するにはどうすればよいですか(例:sed
)を使用していますか?
入力ファイルの例:
Col1 Col2 Col3
A B C
D F
G H I
J K
出力ファイルの例:
Col1 Col2 Col3
A B C
G H I
フィールドに空白を含めることができない場合、空のフィールドは最初の文字としてのタブ(^\t
)、最後の文字としてのタブ(\t$
)、または2つの連続するタブ(\t\t
)。したがって、これらのいずれかを含む行をフィルターで除外できます。
grep -Ev $'^\t|\t\t|\t$' file
空白を使用できる場合、状況はさらに複雑になります。フィールドがスペースで始まる場合は、代わりにこれを使用してください(スペースのみのフィールドは空であると見なされます)。
grep -Pv '\t\s*(\t|$)|\t$|^\t' file
この変更により、タブに一致する行の後に0個以上のスペースが続き、さらに別のタブまたは行の終わりが除外されます。
最後のフィールドにスペースしか含まれていない場合も失敗します。これも回避するには、Perl
を-F
および-a
オプションとともに使用して、入力を@F
配列に分割し、フィールドの1つが空でない限り印刷するように指示します( /^$/
):
Perl -F'\t' -lane 'print unless grep{/^$/} @F' file
awk
の場合:
awk -F"\t" '$1!=""&&$2!=""&&$3!=""' file
実際にはは単純です。
awk
は、\t
フラグで指定されたフィールド区切りタブ-F
で入力を分割します。コンテンツのフィールドにスペースがない場合、これも省略できます。$1!=""&&...
は条件です。この条件が真の場合、awk
は単に行を出力します。 '$1!=""&&$2!=""&&$3!=""{print}'
と書くこともできますが、その必要はありません。 Awksのデフォルトの動作では、アクションが指定されていない場合、行が印刷されます。ここでは、フィールド$1
、$2
、および$3
がすべて空ではない場合、つまり最初の3つのフィールドに値がある場合、その条件はtrueです。別のファイルに書き込むには、これを使用します。
awk -F"\t" '$1!=""&&$2!=""&&$3!=""' input_file >output_file
編集:未定義の列数を使用すると、このawk
を使用でき、行のすべてのフィールドがチェックされます。
awk -F"\t" '{for(i=1;i<=NF;i++){if($i==""){next}}}1' file
awk 'NF==3' file
フィールド数が3の場合、行を出力します。データに応じて列数を変更するのは非常に簡単です。
ただし、指摘したように、これは、可変数のフィールドというOPの要件では機能しません。
あなたはこのようなことを試すことができます:
_grep "^[a-zA-Z0-9]\+[[:space:]][a-zA-Z0-9]\+[[:space:]][a-zA-Z0-9]\+$" input_file > output_file
_
grep
の目的は、特定のパターンに一致する1つ以上のファイルで文字列を検索する(または検索しない)ことです。ここで、パターン_[a-zA-Z0-9]\+
_は、空白またはタブが後に続く1つ以上の英数字に一致します。行の先頭は_^
_と一致しますが、_$
_は行の終わりを示します。列で他の文字が使用されている場合は、上記の文字クラスに追加する必要があります。最後に、_>
_は一致した出力を出力ファイルにリダイレクトします。
潜在的な落とし穴と代替ソリューションについては、以下の@terdonのコメントもご覧ください。 Linux/Unix環境で作業している場合、grep
の有用性はこの特定のソリューションをはるかに超えています。
このタスクを実行するより一般的な方法があります
<$your_file Perl -CASD -ne 'print if not grep { /^$/ } split "\t"'
@terdon:あなたは正しい、今それは期待通りに機能します。