粗大メモ置き場

個人用,たまーに来訪者を意識する雑記メモ

Python文字列で書かれた行列・配列を数値に変換したい(jsonの読み方も含む)

正直いい方法がないか教えてくださいって感じです。

問題の全貌:なんでテキストで行列保存するねん。

jsonファイルとか最近読み込まなきゃいけない時があるのですが,そこからちゃんとデータを読み出すの大変じゃない?
ってお話です。
"[1.1,2.2]"っていう文字列から配列に起こすのが面倒というので

jsonファイル読み出し

例えば次のようなjsonファイルがあったとします。

{ 
  total: "15", 
  page: "1", 
  records: "15",
  rows :
  [
    {cell:"[1, 1]"},
    {cell:"[2, "2]"},
    {cell:"[15, 15]"},
  ]
}

読み出しはpython

import json
with open('data.json') as data_file:    
    data = json.load(data_file)

以下のように書かないのは用がないなら開いたらすぐ閉じるべきという思想があるのでしょう。

f = open('data.json', 'r')
jsonData = json.load(f)

該当データへのアクセス

基本的には,
total: "15", ...となっていたら

a = data[total]

とすればaに "15"が格納されるという仕組みです。

階層構造になっている場合はdata[hoge][fuga][]...とつなげていきます。
また,カッコが{でなくて[になっている場合は配列ですので

b = data[rows][0][cell]

とうてばbに"[1, 1]"が格納されます。
はいではこれをどうしましょうという話です。

python文字列から数値へのキャスト

単一の数字なら簡単です。int()やfloat()に文字列をぶち込むだけです。

文字を並べたときのキャスト

"1.1,2.2"ときた場合はこう上手くは生きません。
そういうのはcsvにしてくれよ…。

numpyを使うと楽になるとか。

>>> np.fromstring('\x01\x02', dtype=np.uint8)
array([1, 2], dtype=uint8)
>>> np.fromstring('1 2', dtype=int, sep=' ')
array([1, 2])
>>> np.fromstring('1, 2', dtype=int, sep=',')
array([1, 2])
>>> np.fromstring('\x01\x02\x03\x04\x05', dtype=np.uint8, count=3)
array([1, 2, 3], dtype=uint8)

解決策(Not smart)

しかしてこの解決策は以下のようになる...のかなぁ
Python 2.7 convert 2d string array to float array - Stack Overflow

あとはnumpyから配列へと変換をしちゃえばっと。

解決策(Not smart)

astとjsonをロードしたあわせ技があります。短いですが欠点はevalを使っていること。
stackoverflowでも非難されていました。

numpy.array(ast.literal_eval(', '.join(data.split(' '))))

convert string representation of array to numpy array in python - Stack Overflow

多分これで動くけど私は結局ヒューマンデコードしましたよね。(クソ)(技術の敗北)(人間はかしこいのです)

関連して

似たような問題も知っておくとイライラを防げそうです。
python - Convert string to numpy array - Stack Overflow