« ワンライナーで実践する簡単データ処理(その2 疑似データベース編) | トップページ | Mac mini Early 2009にMojaveをインストールしてみる »

2018.10.14

tsvファイルからShell Scriptやコマンドを組み合わせてJSON生成

ワンライナーで実践する簡単データ処理(その1 繰り返し項目集計編)
ワンライナーで実践する簡単データ処理(その2 疑似データベース編)
では、シェルスクリプトを使って簡単な集計作業を行いました。

今回は、JSON操作を行ってみます。

例として、前回同様、論文の書誌データを取り上げます。タブ区切りのテキストファイルsavedrecs_0001_2440.txtを


$ cat savedrecs_0001_2440.txt | cut -f9,10,45,23,63 | awk -F'\t' 'BEGIN{OFS="\t"}{print $5,$3,$1,$2,$4}' > temp11.txt

して作成した、以下のタブ区切りテキストファイルtemp11.txtをスタートにしましょう。

UT C1 TI SO PY
WOS:000208617000010 [Chang, Chih-Chung; Lin, Chih-Jen] Natl Taiwan Univ, Dept Comp Sci, Taipei 106, Taiwan LIBSVM: A Library for Support Vector Machines ACM TRANSACTIONS ON INTELLIGENT SYSTEMS AND TECHNOLOGY 2011
WOS:000256047300004 [Bay, Herbert; Ess, Andreas; Van Gool, Luc] ETH, BIWI, CH-8092 Zurich, Switzerland; [Tuytelaars, Tinne; Van Gool, Luc] Katholieke Univ Leuven, ESAT PSI, B-3001 Louvain, Belgium Speeded-Up Robust Features (SURF) COMPUTER VISION AND IMAGE UNDERSTANDING 2008
WOS:000261846800002 [Wright, John; Ganesh, Arvind; Ma, Yi] Univ Illinois, Coordinated Sci Lab, Urbana, IL 61801 USA; [Yang, Allen Y.; Sastry, S. Shankar] Univ Calif Berkeley, Dept Elect Engn & Comp Sci, Berkeley, CA 94720 USA Robust Face Recognition via Sparse Representation IEEE TRANSACTIONS ON PATTERN ANALYSIS AND MACHINE INTELLIGENCE 2009
.....

UTはアクセッション番号(主キー)、C1は著者、所属機関とその国籍/地域、TIは論文タイトル、SOは論文誌、PYは発行年です。

【前処理】
ワンライナーで実践する簡単データ処理(その1 繰り返し項目集計編)
ワンライナーで実践する簡単データ処理(その2 疑似データベース編)
のスクリプトを一部見直してまとめ、以下のようにコマンドを実行しました。


$ TAB=$(printf '\t');LF=$(printf '\\\012_');LF=${LF%_};cat temp11.txt | sed '1,1d' | cut -f1,2 | sed 's/; \[/'"$LF"'\[/g' | awk -F'\t' 'BEGIN{OFS="\t"}{if(NF==2) {UT=$1;print $1,$2} else {print UT,$1}}' | sed 's/^\(.*\)'"$TAB"'\[\(.*\)\] \(.*\)$/\1'"$TAB"'\3'"$TAB"'\2/' | awk -F '\t' 'BEGIN{OFS="\t"}{c=split($2,a,", ");if(a[c]~/USA$/){a[c]="USA"};print $1, a[1], a[c], $3}' | sed 's/; /'"$LF"'/g' | awk -F '\t' 'BEGIN{OFS="\t"}{if(NF==4){P1=$1;P2=$2;P3=$3;print $1,$2,$3,$4}else{print P1,P2,P3,$1}}' | sort | uniq > temp12.txt

以下のようなファイルが出力されました。

....
WOS:000208617000010 Natl Taiwan Univ Taiwan Chang, Chih-Chung
WOS:000208617000010 Natl Taiwan Univ Taiwan Lin, Chih-Jen
....
WOS:000256047300004 ETH Switzerland Bay, Herbert
WOS:000256047300004 ETH Switzerland Ess, Andreas
WOS:000256047300004 ETH Switzerland Van Gool, Luc
WOS:000256047300004 Katholieke Univ Leuven Belgium Tuytelaars, Tinne
WOS:000256047300004 Katholieke Univ Leuven Belgium Van Gool, Luc
....
WOS:000261846800002 Univ Calif Berkeley USA Sastry, S. Shankar
WOS:000261846800002 Univ Calif Berkeley USA Yang, Allen Y.
WOS:000261846800002 Univ Illinois USA Ganesh, Arvind
WOS:000261846800002 Univ Illinois USA Ma, Yi
WOS:000261846800002 Univ Illinois USA Wright, John
WOS:000261846800005 Nanyang Technol Univ Singapore Tao, Dacheng
WOS:000261846800005 Univ London England Li, Xuelong
WOS:000261846800005 Univ London England Maybank, Stephen J.
WOS:000261846800005 Univ Vermont USA Wu, Xindong
...

最後に、temp12.txtにタイトルフィールド、論文誌フィールド、発行年フィールドをjoinします。

$ cat temp11.txt | sort -k1 | join -1 1 -2 1 -t "$(printf '\t')" -o 1.1,2.3,2.4,2.5,1.2,1.3,1.4,1.5 temp12.txt - > temp13.txt

こうしてtemp13.txtを作成しました。内容は以下のとおり。

....
WOS:000208617000010 LIBSVM: A Library for Support Vector Machines ACM TRANSACTIONS ON INTELLIGENT SYSTEMS AND TECHNOLOGY 2011 Natl Taiwan Univ Taiwan Chang, Chih-Chung
WOS:000208617000010 LIBSVM: A Library for Support Vector Machines ACM TRANSACTIONS ON INTELLIGENT SYSTEMS AND TECHNOLOGY 2011 Natl Taiwan Univ
....
WOS:000256047300004 Speeded-Up Robust Features (SURF) COMPUTER VISION AND IMAGE UNDERSTANDING 2008 ETH Switzerland Bay, Herbert
WOS:000256047300004 Speeded-Up Robust Features (SURF) COMPUTER VISION AND IMAGE UNDERSTANDING 2008 ETH Switzerland Ess, Andreas
WOS:000256047300004 Speeded-Up Robust Features (SURF) COMPUTER VISION AND IMAGE UNDERSTANDING 2008 ETH Switzerland Van Gool, Luc
WOS:000256047300004 Speeded-Up Robust Features (SURF) COMPUTER VISION AND IMAGE UNDERSTANDING 2008 Katholieke Univ Leuven Belgium Tuytelaars, Tinne
WOS:000256047300004 Speeded-Up Robust Features (SURF) COMPUTER VISION AND IMAGE UNDERSTANDING 2008 Katholieke Univ Leuven Belgium Van Gool, Luc
....
WOS:000261846800002 Robust Face Recognition via Sparse Representation IEEE TRANSACTIONS ON PATTERN ANALYSIS AND MACHINE INTELLIGENCE 2009 Univ Calif Berkeley USA Sastry, S. Shankar
WOS:000261846800002 Robust Face Recognition via Sparse Representation IEEE TRANSACTIONS ON PATTERN ANALYSIS AND MACHINE INTELLIGENCE 2009 Univ Calif Berkeley USA Yang, Allen Y.
WOS:000261846800002 Robust Face Recognition via Sparse Representation IEEE TRANSACTIONS ON PATTERN ANALYSIS AND MACHINE INTELLIGENCE 2009 Univ Illinois USA Ganesh, Arvind
WOS:000261846800002 Robust Face Recognition via Sparse Representation IEEE TRANSACTIONS ON PATTERN ANALYSIS AND MACHINE INTELLIGENCE 2009 Univ Illinois USA Ma, Yi
WOS:000261846800002 Robust Face Recognition via Sparse Representation IEEE TRANSACTIONS ON PATTERN ANALYSIS AND MACHINE INTELLIGENCE 2009 Univ Illinois USA Wright, John
....

データ処理はこのファイルを対象にして行うほうが早いことが多いでしょうね。

【JSONデータ生成】
上のファイルをjson化するわけですが、例えばjqコマンドでtsvを下の手順で単純にjson化すると(jqコマンドで覚えておきたい使い方17個:俺的備忘録 〜なんかいろいろ〜を参考にしました。ありがとうございます。)、


$ cat temp13.txt | jq -s -r -R 'gsub("\"";"") | split("\n") | map(split("\t")) | map({"UT": .[0], "TI": .[1], "SO": .[2], "PY": .[3], "ORG": .[4], "NOR": .[5], "AUT": .[6]})' | less

できたjson形式データは、

[
{
"UT": "WOS:000207567300006",
"TI": "Bregman Iterative Algorithms for l(1)-Minimization with Applications to Compressed Sensing",
"SO": "SIAM JOURNAL ON IMAGING SCIENCES",
"PY": "2008",
"ORG": "Columbia Univ",
"NOR": "USA",
"AUT": "Goldfarb, Donald"
},
{
"UT": "WOS:000207567300006",
"TI": "Bregman Iterative Algorithms for l(1)-Minimization with Applications to Compressed Sensing",
"SO": "SIAM JOURNAL ON IMAGING SCIENCES",
"PY": "2008",
"ORG": "Rice Univ",
"NOR": "USA",
"AUT": "Yin, Wotao"
},
....
}
]

…形式は確かにjsonですが、jsonらしく構造化されてないですね。

json形式データとして欲しいのは、


{
"BIB" :
[
{
"UT" : "WOS:000208617000010",
"TI" : "LIBSVM: A Library for Support Vector Machines",
"SO" : "ACM TRANSACTIONS ON INTELLIGENT SYSTEMS AND TECHNOLOGY",
"PY" : 2011,
"ONA" :
[
{
"ORG" : "Natl Taiwan Univ ",
"NOR" : "Taiwan",
"AUT" :
[
"Chang, Chih-Chung",
"Lin, Chih-Jen"
]
}
]
},
...
{ ...
}
]
}

のようなjson形式データになりましょうか(これは、イメージです)。

jqは非常に機能が多いコマンド(言語?)なので、単独で結構いろいろできるのですが、この問題について私にはうまいやり方が思いつかず…

joコマンドというものもありますが、入れ子があると結構複雑で、テスト用に小さいトランザクションを作るには便利そうなのですが、まとまったデータ量とある程度複雑な構造になってくると適用が大変そうな印象です。

そこで、ここでは、別のコマンドなり言語と組み合わせてみます。

JSON生成のための前処理スクリプトは、さすがにワンライナーではちょっと無理、ということで、ワンラーナーではないですが、こんなスクリプトを作成してみました。
temp14.sh


#! /bin/sh

sed 's/"/\\\"/g' |
awk -F'\t' \
'BEGIN {
pr1="";pr2="";pr3="";pr4="";pr5="";pr6="";pr7="";
o="";o1="";n1=1;t1="";
}
{
if ($1 != pr1 && NR > 1) {
printf("{\"UT\":\"%s\", \"TI\":\"%s\",\"SO\":\"%s\", \"PY\":%s, \"ONA\":[%s]}\n", pr1, pr2, pr3, pr4, o);
o1="{\"ORG\":\"" $5 "\", \"NOR\":\"" $6 "\", ";
t1="\"" $7 "\"";
o=o1 "\"AUT\":[" t1 "]}";
n1=2;
pr1=$1;pr2=$2;pr3=$3;pr4=$4;pr5=$5;pr6=$6;pr7=$7;
} else {
if ($5 == pr5 && $6 == pr6) {
t1=t1 ", \"" $7 "\"";
o=o1 "\"AUT\":[" t1 "]}";
} else {
if (n1 > 1) {sep=",";o1=o1 "\"AUT\":[" t1 "]}";} else {sep=""}
o1=o1 sep "{\"ORG\":\"" $5 "\", \"NOR\":\"" $6 "\", ";
t1="\"" $7 "\"";
o=o1 "\"AUT\":[" t1 "]}";
n1++;
}
pr1=$1;pr2=$2;pr3=$3;pr4=$4;pr5=$5;pr6=$6;pr7=$7;
}
}
END {
printf("{\"UT\":\"%s\", \"TI\":\"%s\",\"SO\":\"%s\", \"PY\":%s, \"ONA\":[%s]}\n", pr1, pr2, pr3, pr4, o);
}'

$ cat temp13.txt | ./temp14.sh | jq -s '. | {BIB: .}' > temp14.json
できたjsonファイルは以下のとおり。
{
  "BIB": [
    {
      "UT": "WOS:000207567300006",
      "TI": "Bregman Iterative Algorithms for l(1)-Minimization with Applications to Compressed Sensing",
      "SO": "SIAM JOURNAL ON IMAGING SCIENCES",
      "PY": 2008,
      "ONA": [
        {
          "ORG": "Columbia Univ",
          "NOR": "USA",
          "AUT": [
            "Goldfarb, Donald"
          ]
        },
        {
          "ORG": "Rice Univ",
          "NOR": "USA",
          "AUT": [
            "Yin, Wotao"
          ]
        },
        {
          "ORG": "Univ Calif Los Angeles",
          "NOR": "USA",
          "AUT": [
            "Darbon, Jerome",
            "Osher, Stanley"
          ]
        }
      ]
    },
   ...
    {
      "UT": "WOS:000430125500004",
      "TI": "State of the Science of Neural Systems in Late-Life Depression: Impact on Clinical Presentation and Treatment Outcome",
      "SO": "JOURNAL OF THE AMERICAN GERIATRICS SOCIETY",
      "PY": 2018,
      "ONA": [
        {
          "ORG": "Univ Connecticut",
          "NOR": "USA",
          "AUT": [
            "Manning, Kevin J.",
            "Steffens, David C."
          ]
        }
      ]
    }
  ]
}
めでたしめでたし…じゃなくて、なんだかawkでjsonジェネレーターもどきを作っちゃってませんか?それも使い捨ての。 この例では、jqコマンドは、BIBオブジェクト生成とjson整形だけの役割になってしまってます。

これは、なんかおかしい、ということで、考え直してみましょう。
秘密結社シェルショッカー 日本支部 が提供しているシェルスクリプト開発用コマンドに含まれている、makrj.shを使ってみます。
temp15.sh


#! /bin/sh

awk -F'\t' \
'BEGIN {
pr1="";pr5="";pr6="";
n1=-1;n2=-1;n3=-1;
}
{
if ($1 != pr1) {
n1++;
n2=-1;n3=-1;
print "$.BIB[" n1 "].UT", $1;
print "$.BIB[" n1 "].TI", $2;
print "$.BIB[" n1 "].SO", $3;
print "$.BIB[" n1 "].PY", $4;
}
if ($1 != pr1 || $5 != pr5 || $6 != pr6) {
n2++;
print "$.BIB[" n1 "].ONA[" n2 "].ORG", $5;
print "$.BIB[" n1 "].ONA[" n2 "].NOR", $6;
}
n3++;
print "$.BIB[" n1 "].ONA[" n2 "].AUT[" n3 "]", $7;
pr1=$1;pr5=$5;pr6=$6;
}'


$ cat temp13.txt | ./temp15.sh | makrj.sh | less
$ cat temp13.txt | ./temp15.sh | makrj.sh | jq . | less

コマンドの2行目は、整形のためにjqコマンドを通しています。

temp12.shの処理結果である中間データは以下のとおり。


$.BIB[0].UT WOS:000207567300006
$.BIB[0].TI Bregman Iterative Algorithms for l(1)-Minimization with Applications to Compressed Sensing
$.BIB[0].SO SIAM JOURNAL ON IMAGING SCIENCES
$.BIB[0].PY 2008
$.BIB[0].ONA[0].ORG Columbia Univ
$.BIB[0].ONA[0].NOR USA
$.BIB[0].ONA[0].AUT[0] Goldfarb, Donald
$.BIB[0].ONA[1].ORG Rice Univ
$.BIB[0].ONA[1].NOR USA
$.BIB[0].ONA[1].AUT[1] Yin, Wotao
$.BIB[0].ONA[2].ORG Univ Calif Los Angeles
$.BIB[0].ONA[2].NOR USA
$.BIB[0].ONA[2].AUT[2] Darbon, Jerome
$.BIB[0].ONA[2].AUT[3] Osher, Stanley
$.BIB[1].UT WOS:000207567500003
$.BIB[1].TI A New Alternating Minimization Algorithm for Total Variation Image Reconstruction
$.BIB[1].SO SIAM JOURNAL ON IMAGING SCIENCES
$.BIB[1].PY 2008
$.BIB[1].ONA[0].ORG Nanjing Univ
$.BIB[1].ONA[0].NOR Peoples R China
$.BIB[1].ONA[0].AUT[0] Yang, Junfeng
$.BIB[1].ONA[1].ORG Rice Univ
...

シェルスクリプトの処理ですが、tsvファイルをJSONPath-Value形式に変換してmakrj.shに流しています。tsvファイルがソートされているので、前の項目から変化があれば、カウンタ(兼フラグ)をカウントアップしつつ適宜必要な行のみJSONPath-Value形式にデータを流す、という比較的直感的かつ単純な処理で済ませることができます。

(おまけ)
temp14.shを見直したtemp14-2.shを作ってみましたが、結局閉じ括弧処理や連結記号の処理が煩雑になってしまいますので、temp15.shの方が書くのが数段簡単です。


#! /bin/sh

sed 's/"/\\\"/g' |
awk -F'\t' \
'BEGIN {
pr1="";pr2="";pr3="";pr4="";pr5="";pr6="";pr7="";
f1=0;f2=0;
}
{
if ($1 != pr1) {
if (NR > 1) {
print "]}]}";
}
printf("{\"UT\":\"%s\", \"TI\":\"%s\",\"SO\":\"%s\", \"PY\":%s, \"ONA\":[", $1, $2, $3, $4);
f1=0;f2=0;
}
if ($1 != pr1 || $5 != pr5 || $6 != pr6) {
if (f2 == 1) {printf("]}, ");}
printf("{\"ORG\":\"%s\", \"NOR\":\"%s\", \"AUT\":[", $5, $6);
f1=0;
}
if (f1 == 1) {sep=", ";} else {sep="";}
printf("%s\"%s\"", sep, $7);
f1=1;f2=1;
pr1=$1;pr2=$2;pr3=$3;pr4=$4;pr5=$5;pr6=$6;pr7=$7;
}
END {
print "]}]}";
}'

|

« ワンライナーで実践する簡単データ処理(その2 疑似データベース編) | トップページ | Mac mini Early 2009にMojaveをインストールしてみる »

パソコン・インターネット」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック


この記事へのトラックバック一覧です: tsvファイルからShell Scriptやコマンドを組み合わせてJSON生成:

« ワンライナーで実践する簡単データ処理(その2 疑似データベース編) | トップページ | Mac mini Early 2009にMojaveをインストールしてみる »