裏 RjpWiki

Julia ときどき R, Python によるコンピュータプログラム,コンピュータ・サイエンス,統計学

AWK と R のコラボレーション 定式化された入力ファイルからデータファイルへ

2022年09月07日 | ブログラミング

一般解は

https://stackoverflow.com/questions/69385888/parse-multi-line-result-text-file-with-awk-bash-or-r

にあった。AWK スクリプトを平易に書き変えた。


★ 以下のような定式化された入力ファイル melting.txt 

  The MELTING results are :

 Enthalpy : -181,100 cal/mol ( -756,998 J /mol)

 Entropy : -467.3 cal/mol-K ( -1,953.31 J /mol-K)

 Melting temperature : 75.13 degrees C.


  The MELTING results are :

 Enthalpy : -170,800 cal/mol ( -713,944 J /mol)

 Entropy : -444 cal/mol-K ( -1,855.92 J /mol-K)

 Melting temperature : 70.6 degrees C.

からデータを取り出し,R で

  Enthalpy Entropy MeltingTemperature
1  -181100  -467.3              75.13
2  -170800  -444.0              70.60

のようなデータフレームを作る。

★ 用意する AWK スクリプト melting.awk

/Enthalpy/ || /Entropy/ { # "Enthalpy" または "Entropy" を含む行について
    n = split($0, a, " ") # 空白でフィールドに区切る
    gsub(",", "", a[3])   # a[3] が求めるデータである。数値区切りの「,」を消去する
    printf "%g, ", a[3]   # 書き出す
}
/Melting temperature/ {   # "Melting temperature" を含む行について
    n = split($0, a, " ") # 空白でフィールドに区切る
    print a[4]            # 求めるデータ a[4] を書き出す
}

★ R コンソールで以下を実行する。

CSV ファイルに結果を書き出す。
以下で |> を使っているが,tidyverse ではなく Base R のパイプである。
最初の文字列がコンソールで入力されるコマンドである。(脚注参照)

"awk -f melting.awk melting.txt" |>
    pipe() |>
    readLines() |>
    write("results.csv")

後は,ありふれた処理。CSV ファイルをデータフレームに読み込むだけである。

df = read.csv("results.csv", header=FALSE,
         col.names=c("Enthalpy", "Entropy", "MeltingTemperature"))

出来上がり。

  Enthalpy Entropy MeltingTemperature
1  -181100  -467.3              75.13
2  -170800  -444.0              70.60

なお,入力ファイルがちゃんと同じフォーマットであることを仮定している。
その仮定ができない場合の処理を AWK スクリプトに含めるかどうかは,程度問題。

==========
脚注

以下の一行をコンソールで入力すれば

$ > awk -f melting.awk melting.txt 

以下が表示される

-181100, -467.3, 75.13
-170800, -444, 70.6

結果をファイルに入れるには出力を results.csv へリダイレクトすればよい。

$ > awk -f melting.awk melting.txt > results.csv

=================

なお,R だけでやろうとすると以下のようにもなるだろうか。

txt = readLines("melting.txt")
df = NULL
x = NULL
for (i in 1:length(txt)) {
	if (grepl("Enthalpy", txt[i]) || grepl("Entropy", txt[i])) {
		target = sub(",", "", unlist(strsplit(txt[i], " "))[4])
		x = append(x, target)
	} else if (grepl("Melting temperature", txt[i])) {
		x = append(x, unlist(strsplit(txt[i], " "))[5])
		df = rbind(df, x)
		x = NULL
	}
}
df = as.data.frame(df, col.names=c("Enthalpy", "Entropy", "MeltingTemperature"))
print(df)

Julia でやろうとすると以下のようになる(書式に関して別の仮定を置く)

using DataFrames
txt = readlines("melting.txt")
x = Float64[]
for s in txt
    pos = findfirst(r"[-+]?[0-9,]+\.?[0-9]*", s)
    isnothing(pos) == false && append!(x, parse(Float64, replace(s[pos], "," => "")))
end
df = DataFrame(Matrix(reshape(x, 3, :)'), ["Enthalpy", "Entropy", "MeltingTemperature"])
コメント    この記事についてブログを書く
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする
« AWK で製表 | トップ | Julia 1.8.1 が公開されました »
最新の画像もっと見る

コメントを投稿

ブログ作成者から承認されるまでコメントは反映されません。

ブログラミング」カテゴリの最新記事