이름에 "만성"이라는 단어가 포함된 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카운터가 0이 아닐 때, c출력이 첫 번째 필드가 아닐 때 필드 사이에 OFS를 추가하는 데에도 카운터가 사용됨) 개행을 인쇄하고, 그렇지 않으면 아무것도 인쇄하지 않고 c0으로 재설정합니다.

답변3

필드 이름이 다음과 같이 .csv 파일의 첫 번째 줄에 있다고 가정합니다.

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

다음 Perl 코드 한 줄은 필드 이름에 "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 프로그래밍 언어 계열의 언어입니다. 유니코드와 강력한 정규식 구현에 대한 고급 지원을 제공합니다.

Raku의 Text::CSV모듈은 유효한 CSV를 구문 분석하고 유효한 CSV를 출력할 수 있습니다. 대체 열 구분 기호(예: 탭)를 허용해야 하거나 인용된 필드, 빈 필드, 삽입된 줄바꿈 및/또는 쉼표 등을 처리하는 방법이 필요한 경우 아래 Markdown 문서를 확인하세요.

위의 방법은 열 이름으로 CSV 파일을 읽고 필터링하는 매우 강력하지만 장황한 방법입니다. 즉, 헤더를 두 번 읽고 정규식을 사용하여 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 파일을 한 줄씩 메모리로 읽어옵니다. 아래 코드는 @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

관련 정보