いくつかの大きな .csv ファイルがあり、このファイルをバイナリ (1 と 0) 形式に変換したいと思います。最初の2つのフィールドを除いて、テキストを含むすべてのセルは1になり、0は0のままです。
head Test.csv
Iss1,1,0,0,Hsapiens-I34,0,0,0,Mmusculus-H01,0,0
Iss1,11,0,Scerevisiae-U09,Hsapiens-I05,0,0,0,0,0,0
Iss1,21,0,0,Hsapiens-I05,0,0,0,Hsapiens-I31,0,0
Iss1,31,0,0,Mmusculus-H13,0,0,0,0,0,Hsapiens-I31
Iss1,41,0,Scerevisiae-U09,0,0,0,0,0,0,Hsapiens-I21
Iss1,51,0,0,0,0,0,0,Scerevisiae-U25,0,Hsapiens-I21
Iss1,61,0,0,Hsapiens-I34,0,0,0,Mmusculus-H13,0,0
予想される結果は
head Test.csv
Iss1,1,0,0,1,0,0,0,1,0,0
Iss1,11,0,1,1,0,0,0,0,0,0
Iss1,21,0,0,1,0,0,0,1,0,0
Iss1,31,0,0,1,0,0,0,0,0,1
Iss1,41,0,1,0,0,0,0,0,0,1
Iss1,51,0,0,0,0,0,0,1,0,1
Iss1,61,0,0,1,0,0,0,1,0,0
ここで、ファイル内のすべてのテキストは1に変換されます。
誰もがこの問題を克服する方法についてアドバイスをすることができれば非常に感謝します。
ありがとう
答え1
一緒にawk
できること:
awk 'BEGIN {FS=OFS=","} {for (i=3;i<=NF;i++) {$i==0?1:$i=1}} 1' test.csv
BEGIN {FS=OFS=","}
- 入力と出力の区切り文字をコンマに設定します。for (i=3;i<=NF;i++)
- 最大フィールド数に達するまでフィールド3を繰り返します。NF
$i==0?1:$i=1
- フィールドが()i
の場合は0
何もせず1
、そうでない場合はフィールドをi
次に設定します。1
1
-1をtrueと解釈awk
し、デフォルトでレコードを印刷します。
@EdMortonのコメントで提案したように、$1=($i!=0)
isを使用する方が短い選択肢です。$i==0?1:$i=1
$i!=0
i
フィールドが次の場合は論理テストです。いいえ0
。それに応じてフィールド値をawk
返し、上書きします。1
true
0
false
答え2
パールの使用:
$ perl -F, -lne 'my @out = map { /^0$/ ? 0 : 1 } splice @F,2;
unshift @out, @F;
print join(",",@out)' Test.csv
Iss1,1,0,0,1,0,0,0,1,0,0
Iss1,11,0,1,1,0,0,0,0,0,0
Iss1,21,0,0,1,0,0,0,1,0,0
Iss1,31,0,0,1,0,0,0,0,0,1
Iss1,41,0,1,0,0,0,0,0,0,1
Iss1,51,0,0,0,0,0,0,1,0,1
Iss1,61,0,0,1,0,0,0,1,0,0
Zed227,28897871,0,0,1,0,0,0,1,0,0
Zed227,28897881,0,1,1,0,0,0,0,0,0
Zed227,28897891,0,0,1,0,0,0,1,0,0
Zed227,28897901,0,0,0,0,0,0,0,0,1
lad1,1,0,1,0,0,0,0,0,0,1
lad1,11,0,1,0,0,0,0,1,0,0
lad1,21,0,0,1,0,0,0,0,0,0
仕組み:
Perlコマンドラインオプション:
- この
-F,
オプションは、Perlにカンマをフィールド区切り文字として使用するように指示します。-F
また、フィールドを含む各入力行を名前付き配列に自動的に分割します@F
。これは、awkがフィールドを$ 1、$ 2、$ 3などに自動的に分割するのと似ています。 -l
入力から改行を削除して出力に再追加するなど、行末を自動的に処理するようにPerlに指示しますprint
。-n
Perlを次のように実行させますsed -n
。つまり、各行を読み取って処理しますが、明示的に指示されたものだけを印刷します。-e
Perlに、次の引数が実行するスクリプトであることを伝えます。
スクリプト:
Perlは
splice()
配列の一部を削除してその部分を呼び出し元に返すので、配列splice @F,2
の最初の2つの要素を除くすべての要素を削除して返します@F
。実際にsplice
はそれより多くのことができますが、ここではここまでしか使いません。perldoc -f splice
詳細より。Perlの
map
関数は、配列(リスト)の各要素に式を適用します。この場合、リストはsplice関数から返された要素です。map
ここで使用される式は、要素が正規表現と一致する場合は1を返し、一致しない場合は1を返します。配列変数に割り当てられた配列を返します。詳細より。0
/^0$/
map
@out
perldoc -f map
ただし、正規表現の代わりに三項
eq
演算子(たとえば)を使用して文字列同等比較を使用できます。$_ eq "0" ? 0 : 1
文字列比較はこの単純な正規表現よりも高速ですが、.csvファイルが非常に大きくない限り(数千行)それほど大きくはありません。それでもeq
使用する方が良いと思います/^0$/
。数値比較(
==
、 ie$_ == 0 ? 0 : 1
)は、数字で始まらない文字列(前のスペースを無視)はゼロと評価されますが、これを1に置き換える必要があるため、必要な操作は実行されません。unshift
逆に、shift
配列の先頭に要素を追加します。この場合、配列の残りの部分@F
(つまり、削除されていない最初の2つの要素)を配列の先頭にsplice
追加します@out
。望むよりperldoc -f unshift
。最後に、
@out
配列はコンマで連結されて印刷されます。使用されるjoin
機能の詳細についてはを参照してくださいperldoc -f join
。
これは単一の声明に縮小することができます。
perl -F, -lne 'print join ",", @F[0..1], map { /^0$/ ? 0 : 1 } splice @F,2' Test.csv
@out
一時変数として必要ではなく、必須ではありませんunshift
。
まったく同じように動作しますが、理解するのは難しいです。特にPerlに慣れていない人にとっては、もっとそうです。各機能がどの入力を受け取るかを知るために、後ろから前に読む必要があります。
答え3
使用幸せ(以前のPerl_6)
~$ raku -ne 'my @a = .split(","); \
@a[2..*] = do for @a[2..*] { $_ ~~ 0.Int ?? 0 !! 1 }; \
@a.join(",").put ;' file
または:
~$ raku -ne 'my @a = .split(","); \
@a[2..*] .= map: { $_ ~~ 0.Int ?? 0 !! 1 }; \
@a.join(",").put ;' file
または:
~$ raku -ne 'my @a = .split(","); \
@a[2..*] .= map: { +( $_ !~~ 0.Int ) }; \
@a.join(",").put;' file
RakuはPerlプログラミング言語シリーズのプログラミング言語です。並行性、非同期、並列性(CAP)の高度なサポートが組み込まれています。
上記の最初の2つのコード例は、@casが投稿した優れたPerlの答えと非常によく似ています。 Rakuには、Rakuメソッドの構文砂糖である非対称の~~
「スマートマッチング」演算子があることに注目する価値があります(.ACCEPTS()
言い換えれば、「RHSはLHSを収容していますか?」)。~~
Rakuの「スマートマッチング」演算子を使用すると、「タイプ」に関連する多くの問題を解決できます。
Rakuはまた、組み込みの三項演算子のための新しいフォーマットを提供しています:(テスト)??
本物 !!
間違った。一部の人々は、この三項演算子が読みやすいと思います。または、3番目の例では、~~
比較後に戻り変数が設定されるという事実を使用して、結果True
/値をFalse
/に渡したり強制したりできます。+(…)
(…).Int
0
1
[上記のコード例では、RHSは.Int
実際に冗長であり、スマートマッチングは追加の強制なしでうまく機能します。ただし、デフォルトで解決されない特定の比較が必要な場合は、LHS / RHSキャスト(.Str
、、.Int
などを介して)を実行できます。.Bool
入力例:
Iss1,1,0,0,Hsapiens-I34,0,0,0,Mmusculus-H01,0,0
Iss1,11,0,Scerevisiae-U09,Hsapiens-I05,0,0,0,0,0,0
Iss1,21,0,0,Hsapiens-I05,0,0,0,Hsapiens-I31,0,0
Iss1,31,0,0,Mmusculus-H13,0,0,0,0,0,Hsapiens-I31
Iss1,41,0,Scerevisiae-U09,0,0,0,0,0,0,Hsapiens-I21
Iss1,51,0,0,0,0,0,0,Scerevisiae-U25,0,Hsapiens-I21
Iss1,61,0,0,Hsapiens-I34,0,0,0,Mmusculus-H13,0,0
出力例:
Iss1,1,0,0,1,0,0,0,1,0,0
Iss1,11,0,1,1,0,0,0,0,0,0
Iss1,21,0,0,1,0,0,0,1,0,0
Iss1,31,0,0,1,0,0,0,0,0,1
Iss1,41,0,1,0,0,0,0,0,0,1
Iss1,51,0,0,0,0,0,0,1,0,1
Iss1,61,0,0,1,0,0,0,1,0,0
注:上記のコードはスペース値、、、00
および0x0
すべて0に-0
変換します。特に、空の値の場合、すべての列が違いを検出するためのパラメータの有無にかかわらず、コードで埋められていることを確認する必要があります。 Perlファンの場合は、Rakuのドキュメントセクションを参照してください。0.0
0
raku -ne '.split(",", :skip-empty).elems.say;'
:skip-empty
「0」は真。
00
0x0
空白の値、、、および-0
別の方法で処理するには、0.0
Perlの回答を確認してください。 @StéphaneChazelasのPerl回答には、これらの値(およびスペース)を処理する方法の説明が含まれています。私の手で@casのPerlの答えは空の値、、、およびallを変更しました(空の値は@StéphaneChazelasのPerlの答えとは異なる方法で処理されます)00
。したがって、あなたには選択肢があります(2つの言語、3つの治療法)!0x0
-0
0.0
1
https://docs.raku.org/言語/operators#infix_??_!!
https://docs.raku.org/routine/ACCEPTS
https://docs.raku.org/routine/~~
https://raku.org
答え4
別のperl
方法は、@F
次のように修正することです。
$ perl -F, -le 'map {$_ &&= 1} @F[2..$#F]; print join ",", @F' test.csv
Iss1,1,0,0,1,0,0,0,1,0,0
Iss1,11,0,1,1,0,0,0,0,0,0
Iss1,21,0,0,1,0,0,0,1,0,0
Iss1,31,0,0,1,0,0,0,0,0,1
Iss1,41,0,1,0,0,0,0,0,0,1
Iss1,51,0,0,0,0,0,0,1,0,1
Iss1,61,0,0,1,0,0,0,1,0,0
要素が1
次のように処理される場合本物つまり、空の0
文字列でも空の文字列でもない場合です。 、または同じゼロの他の表現は、次のよう00
に処理されます。0x0
-0
0.0
zero
本物に変更されました1
。