CSVデータセットをフィルタリングして行を見つけてテキストファイルに保存する

CSVデータセットをフィルタリングして行を見つけてテキストファイルに保存する

私はシェルコマンドを初めて使用します。 CSVデータセットfbnews.csvに基づいて、この問題は少し混乱しています。

CSV データセットは次のとおりです。

D,E,F,   message,                 score,    A,B,C,   ID
d,e,f,  Let's read a book,           24,    a,b,c,    1
j,k,l,   Read this book,             39,    d,e,f,    2
m,n,o,   Have you read this book?,   15,    g,h,i,    3

これは単なる例です。元のデータセットには20,000,000行と20列が含まれています。

このデータセットから

  1. 「read」という単語が含まれ、スコアが20より大きい行を探します。 2.この行では、スコア値に基づいてソートされたスコアとID列のみを印刷します。
  2. これらのソートされた列をテキストファイルに保存します。

予想される出力は次のとおりです。

Score   ID
24      1
39      2

シェルコマンドを使用してこれをどのように実行できますか?

答え1

ミラーの使用(https://github.com/johnkerl/miller)と

D,E,F,message,score,A,B,C,ID
d,e,f,Let's read a book,24,a,b,c,1
j,k,l,Read this book,39,d,e,f,2
m,n,o,Have you read this book?,15,g,h,i,3

そして走っている

mlr --csv filter -S '$message=~"(r|R)ead" && $score>20' then cut -f score,ID input.csv >output.csv

あなたはやる

score,ID
24,1
39,2

コマンドに関するいくつかの詳細は次のとおりです。

  • --csv、入力および出力フォーマットの設定
  • filter -S '$message=~"(r|R)ead" && $score>20'フィルタを適用
  • cut -f score,IDあなたの分野を選択してください

ヘッダー列よりもセルが多い誤ったCSVがある場合

D,E,F,message,score,A,B,C,ID
d,e,f,Let's read a book,24,a,b,c,1
j,k,l,Read this book,39,d,e,f,2,a wrong cell,another wrong cell
m,n,o,Have you read this book?,15,g,h,i,3

raggedオプションを適用して実行できます

mlr --csv --ragged unsparsify then filter -S '$message=~"(r|R)ead" && $score>20' then cut -f score,ID input.csv>output.csv

ただし、CSVに問題がある場合は、ここで内容全体を共有することをお勧めします。

答え2

私は学んでawkいるので、賢い方のフィードバックを楽しみにしています。

cat file | tr -s ' ' | awk -F, 'BEGIN { print "Score ID" } tolower($4) ~ /read/ { if($5 >= 20) print $5,$9 }' > output

この場合、OP形式を使用するには、すべてのスペースを1つに変更します。

tr -s ' '

カンマを区切り文字として使用します。

-F,

比較で大文字と小文字を区別しないようにするには、次のようにします。

tolower($4)

4番目の列には「read」という文字列があります。

tolower($4) ~ /read/

5番目の列の値が20以上の場合は、次のように印刷します。

if($5>=20) print $5,$9

タイトルを追加する(現在、次をawk使用してこれを実行しようとしています。

 BEGIN { print "Score ID" }

出力

score ID
 24  1
 39  2

答え3

私はシェルスクリプトをあまり使用しませんが、他の言語でも同様の作業を頻繁に行います。検索を整理するのに役立ついくつかの点を提供します。

1 - csvファイルを解析する必要があります。

次のリンクからcsvファイルを解析する方法を学ぶことができます。 https://stackoverflow.com/questions/4286469/how-to-parse-a-csv-file-in-bash

2 - 「read」という単語に一致する行を取得する必要があります。

このような正規表現を使用していくつかの基準を調整することで、20.2を超えるスコアをキャプチャできます。

/\b(\w*read\w*)\b/g

式に関する情報を表示するには、このサイトにドロップしてください。https://regexr.com/

3 - 条件に従って出力をソートする必要があります。

あなたはそれを使用することができますタイプこれを実行するコマンドです。配列に割り当て、その配列をソートするよりも簡単です。

4 - 出力リダイレクト

シェル出力を「script.sh> my_output.txt」などのファイルに簡単にリダイレクトできます。または、「var> output.txt」スクリプトでこれを行います。

答え4

いくつかのawk正規表現を使用してからスペースをクリーンアップするためのパイピングcolumn

awk -F',' '{if ( $4 ~ /[Rr]ead/ &&  $5 > 20 || NR==1) print $5, $9}' data.csv | column -t

説明....フィールド区切り記号を次のように設定した後、-F','

~.... 4 番目のフィールドの正規表現が "Read" または "read" と一致し、5 番目のフィールドが&&20 より大きいか、||ヘッダーがある最初の行にある場合、NR==1List に興味のある内容を印刷します。 ....

楽しく

列ヘッダーを知っていますが、計算するのが面倒すぎる場合...

ヘッダーを連想配列にロードする

declare -A HEADS=( [mess]=mess [id]=ID [score]=score )

.....awkデータファイルの最初の行の列インデックスを配列に入れます。

for j in "${!HEADS[@]}"; do HEADS[$j]=$(awk -F',' -v s=${HEADS[$j]} 'NR==1 {for (i=1; i<=NF; ++i) { if ($i ~ s ) print i }}' data.csv) ; done

...トップに戻り、awkインデックスを変数として注入します。

awk -v mess=${HEADS[mess]} -v score=${HEADS[score]} -v id=${HEADS[id]} -F',' '{if ( $mess ~ /[Rr]ead/ &&  $score >20 || NR==1) print $score, $id}' data.csv | column -t

関連情報