一部のセルには複数の値を含む大容量CSVファイルがあります。最小値のみを含むようにこれらのセルをどのように変更できますか?
たとえば、次の入力が与えられた場合:
id,disease_1,disease_2
1001,2008;2009,2009;2010
ノート
- 列/フィールド区切り記号はコンマです。
,
- 各セルの値はセミコロンで区切られ、
;
昇順にソートされます。 - 列2でアルゴリズムを開始したいと思います。
希望の出力:
id,disease_1,disease_2
1001,2008,2009
ベストアンサー1
サブコマンドでput
使用される「式」は次のとおりです。put
ミラー(mlr
;構造化データ操作用に特別に設計されたツール)は、;
各非フィールドから分離された値の最小値を計算しますid
。
for (key,value in mapexcept($*, "id")) {
value !=~ ";" { continue }
var minimum = "";
for (i,number in splitnv(value, ";")) {
minimum = min(minimum, number)
}
$[key] = minimum;
}
ここでは各レコードのフィールドを繰り返しますが、呼び出されるとフィールドはスキップされますid
。フィールド値をセミコロンに分割して生成された数値を繰り返しながら、各フィールドの最小値を追跡します。ループが終了すると、フィールド値は見つかった最小値で上書きされます。含まれていないフィールドは;
ループの開始時にスキップされます。
以下を使用して実行できます。
mlr --csv put -e script file.csv
...script
上記の短いスクリプトを保存するファイル名はどこにありますか?または、次のようにコマンドラインにスペルを入力できます。
mlr --csv put 'for (k,v in mapexcept($*,"id")) { v !=~ ";" { continue } var m=""; for (i,n in splitnv(v,";")) { m=min(m,n) } $[k]=m; }' file.csv
質問のデータを考慮すると、結果は次のようになります。
id,disease_1,disease_2
1001,2008,2009
最新バージョンのMiller(バージョン6+)を使用すると、コードを短縮できます。かなり新しいsort()
sumget_values()
関数を使用すると、次のようになります。
mlr --csv put 'for (k,v in mapexcept($*,"id")) { $[k] = sort(get_values(splitnv(v,";")))[1] }' file.csv
各フィールドの分離値のリストから最初の値を選択します;
。
(ありがとうございます。スチールドライバーこの巧妙な書き換えを悟りました。 )
値がすでにソートされている場合は、はるかに簡単で効率的です。
mlr --csv put 'for (k,v in mapexcept($*,"id")) { $[k] = sub(v,";.*","") }' file.csv
;
これにより、各フィールドの最初の文字が切り捨てられます。