名前に「慢性」という単語を含むCSVファイルから列を抽出する方法

名前に「慢性」という単語を含むCSVファイルから列を抽出する方法

大きなcsvファイル(約1000列)があり、ヘッダー名に「慢性」という単語を含む列だけを新しいファイルに抽出したいと思います。どうすればいいですか?

たとえば、次のような場合があります。

gender,chronic_disease1,chronic_disease2
male,2008,2009

希望の出力は次のとおりです。

chronic_disease1,chronic_disease2
2008,2009

注:列/フィールドの区切り文字はカンマ「、」です。一致するものがない場合、chronic出力はまったくありません。

答え1

使用ミラー(Ubuntuの「ユニバース」リポジトリで利用可能です)対応する動詞cutは、オプションで正規表現を使用してフィールド名を一致させることができます。

mlr --csv cut -r -f 'chronic' file.csv

chronic(フィールド名の部分文字列と一致)またはより具体的に

mlr --csv cut -r -f '^chronic_' file.csv

(サブストリングを名前の先頭に固定し、後ろにアンダースコアを付けます)

mlr --csv cut -r -f '"^chronic_"i' file.csv

後者を大文字と小文字を区別せずに一致させます。

一致を元に戻すには、すべての列を選択してください。いいえ一致^chronic_、追加-x

mlr --csv cut -x -r -f '"^chronic_"i' file.csv

--csvlite注:入力ファイルに高度なCSV機能(RFC-4180スタイルの二重引用符など)が含まれていない場合は、より効率的なエンジンを使用できます。バラよりファイル形式 - CSV/TSV/ASV/USV/など。

文字列を含むフィールド名がなく、空のchronicレコードの代わりに出力がまったく必要ない場合は、skip-trivial-records抽出したデータをMillerのサブコマンドで渡します。

mlr --csv cut -r -f 'chronic' then skip-trivial-records file.csv

答え2

awkを使用してください:

awk '
  BEGIN{ FS=OFS="," }
  NR==1{
         for(i=1; i<=NF; i++)
             found+=col[i]=($i ~ /chronic/)
         if(!found) exit
       }
  {
    for(i=1; i<=NF; i++)
        printf ("%s", (col[i]? (c++?OFS:"")$i :"") )
    printf("%s", (c?"\n" : "") ); c=0
  }' infile.csv

フィールド区切り文字と出力フィールド区切り文字をコンマに設定して、入力ファイルがCSVファイルであることを示します。

最初の入力行(ヘッダー行であると仮定)の場合、col[]その行の各フィールドに部分文字列 "が含まれているかどうかを格納する配列を作成します。慢性病患者その後、TRUE / 1(/chronic/各フィールドを正規表現と一致)またはFALSE / 0(一致しない場合)。

if(!found) exitコードのこの部分は、出力するフィールドがない場合にコマンドを終了し、入力ファイルの処理を停止するように awk に指示します。それ以外の場合...

...その後、各後続の行(および最初の行)に対してその行の各フィールドを繰り返し、そのcol[i]値が1の場合はそのフィールドを印刷し、そうでない場合は行を処理して空の文字列を印刷します。フィールド出力がある場合(cカウンタがゼロでない場合、出力cが最初のフィールドではないときにフィールド間にOFSを追加するためにもカウンタが使用されます)、改行を印刷し、それ以外の場合は何も印刷せずにc0にリセットします。

答え3

フィールド名が次のように.csvファイルの最初の行にあるとします。

$ cat input.csv 
gender,chronic_disease1,chronic_disease2
male,2008,2009

次のPerlコードの1行は、フィールド名に "chronic"文字列を含むフィールドを印刷します。

perl -F, -lane '
  if ($. == 1) {   # first line of input
    # get a list of field numbers & names matching "chronic"
    foreach my $f (0..$#F) {
      if ($F[$f] =~ /chronic/i) { # case-insensitive 
        push @out, $f;            # get the field numbers
        push @outnames, $F[$f];   # get the names too
      }
    };
    last unless (@out);           # exit early if there's nothing to print
  } else {
    print join(",", @outnames) if ($. == 2); # print the header only once
    print join(",", @F[@out])                # print the data
  }' input.csv 

出力例:

chronic_disease1,chronic_disease2
2008,2009

注:これは単純なカンマ区切りファイルでのみ機能します。カンマまたは改行を含む引用符付きフィールドを含むCSVファイルでは機能しません。これを行うには、CSVパーサーを使用する必要があります(Perlのパーサーなど)。テキスト::CSV、またはさらにPerlのDBD::CSVモジュールデータベースインタフェースまるでSQLデータベースのように、CSVファイルに対してSQLクエリを実行できます。または使用ミラー

答え4

使用幸せ(以前のPerl6)

~$ raku -MText::CSV -e '  \

  #read header into @hdr array
      my $csv1 = Text::CSV.new;
      my $fh1 = "chronic_test.txt".IO.open;
      my @hdr = $csv1.header($fh1, munge-column-names => "fc").column-names;
      close $fh1;

  #read full csv file into @whole array
      my $csv2 = Text::CSV.new;
      my $fh2 = "chronic_test.txt".IO.open; 
      my @whole; while $csv2.getline($fh2) -> $row {
      @whole.push: $row;
      }; close $fh2;

  #output array that has been @whole>>.[index] filtered for desired columns
     .join(",").put for @whole>>.[@hdr.grep(/chronic/, :k)];'

入力例:

gender,chronic_disease1,chronic_disease2
male,2008,2009

出力例:

chronic_disease1,chronic_disease2
2008,2009

RakuはPerlプログラミング言語系列の言語です。 Unicodeと強力な正規表現の実装に対する高度なサポートを提供します。

RakuのText::CSVモジュールは有効なCSVを解析し、有効なCSVを出力できます。別の列区切り文字(タブなど)を許可する必要がある場合、または引用符付きフィールド、空白フィールド、挿入された改行、および/またはコンマなどを処理する方法が必要な場合は、以下のMarkdownドキュメントを確認してください。

上記の方法は、列名でCSVファイルを読み取ってフィルタリングする非常に強力ですが、冗談です。つまり、ヘッダーを2回読み込み、正規表現を使用してgrep一致する列を出力します。必要に応じて、列名をmunge別の大文字と小文字(など)に切り替えるucことができます。lcfc

下部のマークダウン文書は、CSVファイルを出力するために次のコードを提供します(必須列のみを出力するように変更されています)。

# and write CSV file, filtered as above
my $fh_out = open "new.csv", :w;
$csv.say($fh_out, $_) for @whole>>.[@hdr.grep(/chronic/, :k)];
$fh_out.close;


より効率的:上記のコードは実際に@wholecsvファイルを1行ずつメモリに読み込みます。以下のコードは@filteredcsv列をメモリに読み込むだけで、メモリ効率が高くなります。

$注:「昇格」 - 署名は非常に重要です。スカラー〜に@署名する大量に次のオブジェクトを使用する場合「位置インデックス」。プロモーションは次の形式であるか、@($index)より簡単にすることができます@$index

~ % raku -MText::CSV -e '  \

  #read header into @hdr array
      my $csv1 = Text::CSV.new;
      my $fh1 = "chronic_test.txt".IO.open;
      my @hdr = $csv1.header($fh1, munge-column-names => "fc").column-names;
      my $index = @hdr.grep(/chronic/, :k); close $fh1;

  #read filtered csv file into @filtered array
      my $csv2 = Text::CSV.new;
      my $fh2 = "chronic_test.txt".IO.open;
      my @filtered; while $csv2.getline($fh2) -> $row {
      @filtered.push: $row.[@$index];
      }; close $fh2;

     .join(",").put for @filtered;'

https://github.com/Tux/CSV/blob/master/doc/Text-CSV.md
https://docs.raku.org
https://raku.org

関連情報