裏 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 で製表

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

以下のような入力ファイル CodeFormat

Code
Format
Example
0
dd-mmm-yyyy HH:MM:SS
07-Sep-2000 15:38:09
1
dd-mmm-yyyy
07-Sep-2000
2
mm/dd/yy
09/07/00
3
mmm
Sep
4
m
S

からデータを読み込み

Code | Format | Example
:--|:--|:--
0 | dd-mmm-yyyy HH:MM:SS | 07-Sep-2000 15:38:09
1 | dd-mmm-yyyy | 07-Sep-2000
2 | mm/dd/yy | 09/07/00
3 | mmm | Sep
4 | m | S

のように整形して出力ファイル table に書き込む。

つまり,最終形の表は3列からなり,各列は | で区切られている。元のデータは3行で表の1行になる。

awk で書くとこんなスクリプト

{
	getline a
	getline b
	printf "%s | %s | %s\n", $0, a, b
}
FNR == 3 {
	print ":--|:--|:--"
}

こんなふうに実行する。

awk -f temp.awk < CodeFormat >table

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

PVアクセスランキング にほんブログ村

PVアクセスランキング にほんブログ村