質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

Q&A

解決済

2回答

1646閲覧

文字列内の辞書型をpandasのデータフレームへ

pyusr

総合スコア12

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

0グッド

0クリップ

投稿2021/04/30 07:48

編集2021/05/01 04:12

前提・実現したいこと

PythonでAPI取得しjson_normalizeでdataframeにしたところ
この要素の中に、さらに辞書型が文字列として入っているため、これをカラムに追加したい
※以下のイメージ

df

date内包データ
2000/01/01"[{'A':'100','B':'200'}]"


やりたいこと

date内包データAB
2000/01/01"[{'A':'100','B':'200'}]"100200

この「内包データ」をdf2と取り出し、カラム追加したいと思うが
Dataframeとして抽出できなく困っています。

該当のソースコード

python

1※pandas as pd 2df = pd.json_normalize( 取得.json() , record_path='data') 3 4※以下失敗した例 5df2 = pd.DataFrame(df['内包データ']) 6df2 = pd.Series(df['内包データ']) 7df2 = pd.DataFrame(df['内包データ'])

dfは問題なくDataframeとして扱える。
上記失敗で気づいたのがdfの内包データのカラムが
そもそもリストでも辞書型でもなく、文字列になっているのが原因と思うが解消ができず

ご教示願います。


(4/30_19:45)ご質問いただきましたので、内容追記します。

取得.json()から確認したところ
以下のような内容でした。ダミーに編集してます。

Python

1{"hasMore": false, "nextPageToken": null, 2"data": [{"id": "AAAAA9999999999", 3    "registeredTime": "2021-04-30T19:19:05+09:00", 4    "updatedTime": "2021-04-30T19:19:06+09:00", 5    "owner": {"id": "ABCDE", "name": "SATO", "email": "dammy@dammy.co.jp"}, 6    "external": [{"id": "AAAAA9999999999", 7        "personId": "AAAAA88888888888888", 8        "lastName": "SUZUKI", 9        "firstName": "TARO"}], 10     …略 }

”data”のカラムをdfとして取得するまでは問題ありませんでした。

「内包データ」と言っていたものは
data内の"external"や"owner"の箇所です。
メールアドレスや日付など、怪しげな半角記号があったので残しましたが
その他の日本語部分などはすべて省略してます
再追記

Python

1dat = r.json()['data'][0] 2 print(json.dumps(dat))

の結果を追記いたします。

Python

1{"id": "AAAAA9999999999", 2    "registeredTime": "2021-04-30T19:19:05+09:00", 3    "updatedTime": "2021-04-30T19:19:06+09:00", 4    "owner": {"id": "ABCDE", "name": "SATO", "email": "dammy@dammy.co.jp"}, 5    "external": [{"id": "AAAAA9999999999", 6        "personId": "AAAAA88888888888888", 7        "lastName": "SUZUKI", 8        "firstName": "TARO"}], 9    "type": "A", 10    "categories": [], 11    "title": null, 12    "location": null, 13    "memo": null}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ppaul

2021/04/30 08:25

"[{'A':'100','B':'200'}]‘" はデータフレームを表示したときに見えているものですか。 言い換えるとこの文字列の0文字目は " ですか、それとも [ ですか?
pyusr

2021/04/30 08:30

失礼しました。  [ かと思います! printで表示すると、"は見えてません。 今回dataframeをCSV出力しており、”と記載しておりました。
can110

2021/04/30 10:31

元データのカタチが問題解決の鍵となるので import json; print( json.dumps( 取得.json()))した結果を提示ください。
pyusr

2021/04/30 10:57

閲覧とコメント、ありがとうございます。 質問内容にて編集・追記いたしました。よろしくお願いします。
can110

2021/04/30 11:22 編集

惜しいことに「…略」の部分が略されすぎているためか、現象が再現できません。 データを絞るために dat = 取得.json()['data'][0] print(json.dumps(dat))の結果を提示ください。
pyusr

2021/04/30 11:41

ありがとうございます。再度結果を追記しました。 問題になりそうな箇所があまり見つからなかったのですが、再現できますでしょうか… よろしくお願いします。
can110

2021/04/30 11:58

正常なデータとして再現できません。 最初は「{」で始まっているのに最後が「]」で終わっています。
pyusr

2021/05/01 04:12

]が余計でした、失礼しました。
bsdfan

2021/05/01 04:38

pandas.json_normalizeで作ったのなら、文字列ではなくdictが入っていると思うのですが。 type(df['内包データ'][0]) はstrではなく、dictになりませんか?
pyusr

2021/05/01 05:01

ありがとうございます!見た目ではなくtypeで判定する方法がありましたね… 結果は「リスト型(list)」となりました。 再度以下で判定し type(df['内包データ'][0][0]) こちらで「辞書型(dict)」となりました。
guest

回答2

0

辞書は常に同じ形をしていると仮定したときの方法です。

1行で書きかかったのですが方法を思いつかなかったので2行です。

python

1>>> print(df) 2 date 内包データ 30 2000/01/01 [{'A':'100','B':'200'}] 41 2000/01/02 [{'A':'300','B':'150'}] 5>>> import ast 6>>> df['A'] = df['内包データ'].apply(lambda x: ast.literal_eval(x)[0]['A']) 7>>> df['B'] = df['内包データ'].apply(lambda x: ast.literal_eval(x)[0]['B']) 8>>> print(df) 9 date 内包データ A B 100 2000/01/01 [{'A':'100','B':'200'}] 100 200 111 2000/01/02 [{'A':'300','B':'150'}] 300 150

エラーが出たとのことですので再現テストを行ってみました。

以下のプログラムを流しました。

python

1import pandas as pd 2df = pd.DataFrame({'date':['2000/01/01', '2000/01/02'], '内包データ':["[{'id': 'ABCDE9999999','lastName': '鈴木', 'firstName': '太郎'}]", "[{'id': 'ABCDE8888888','lastName': '佐藤', 'firstName': '花子'}]"]}) 3print(df) 4import ast 5df['id'] = df['内包データ'].apply(lambda x: ast.literal_eval(x)[0]['id']) 6df['lastName'] = df['内包データ'].apply(lambda x: ast.literal_eval(x)[0]['lastName']) 7df['firstName'] = df['内包データ'].apply(lambda x: ast.literal_eval(x)[0]['firstName']) 8print(df)

実行結果は以下です。

python

1>>> df['id'] = df['内包データ'].apply(lambda x: ast.literal_eval(x)[0]['id']) 2>>> df['lastName'] = df['内包データ'].apply(lambda x: ast.literal_eval(x)[0]['lastName']) 3>>> df['firstName'] = df['内包データ'].apply(lambda x: ast.literal_eval(x)[0]['firstName']) 4>>> print(df) 5 date 内包データ id lastName firstName 60 2000/01/01 [{'id': 'ABCDE9999999','lastName': '鈴木', 'firs... ABCDE9999999 鈴木 太郎 71 2000/01/02 [{'id': 'ABCDE8888888','lastName': '佐藤', 'firs... ABCDE8888888 佐藤 花子

投稿2021/04/30 08:33

編集2021/04/30 12:08
ppaul

総合スコア24670

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pyusr

2021/04/30 09:01

ご回答ありがとうございます! applyとlambdaで絞込、カラム追加をする。というイメージでしょうか 調べた中にあったのですがうまくできず、「ast」を使用したことがなかったので勉強になります。 しかし試したところ、エラーが出てしまいました… (検索してみたのですが、解決できずコメントいたします) 以下の表記でした。   ValueError: malformed node or string: どのような解決法が考えられるでしょうか? ※「内包データ」の中身が数値ではなく文字の箇所も多いのですが関係ありますか? ご教示いただけると幸いです!
ppaul

2021/04/30 09:36

問題が起きたデータを教えてください。
pyusr

2021/04/30 10:13

内包データのカラム中身は以下のようなものです。ダミーに書き換えております。 [{'id': 'ABCDE9999999','lastName': '鈴木', 'firstName': '太郎'}] [{'id': 'ABCDE8888888','lastName': '佐藤', 'firstName': '花子'}] など
ppaul

2021/04/30 12:11

回答に再現テストのコードとその結果を追加しました。 こちらでは正常に動作しました。 同じ再現テストを流してみてください。 それが正常に動くようなら、「ダミーに書き換え」では現れて居ない部分が原因ということになります。 その場合は、再現するようなデータを教えてください。
pyusr

2021/05/01 04:10

追記ありがとうございます。再現テストの内容では正常に動作しました。 が、やはり本番データでは不可能でした。 書き換え箇所がいくつかあったので、再度日本語以外は書き換えずエラー内容を記載します。 ValueError: malformed node or string: [{'id': '67E64A3F5A371D8837D5DEE505411B57', 'personId': 'C802B7678F79F0BBE697225CF837B518', 'companyName': '株式会社A', 'lastName': '鈴木', 'firstName': '太郎'}]
guest

0

ベストアンサー

内包表記列が文字列ではなくlistになっているとのことなので、次のようにしたらできると思います。
applyで、dictをSeriesに変換するようにしたらよいです。

python

1import pandas as pd 2 3df = pd.DataFrame( 4 {'date': ['2000/01/01', '2000/01/02'], 5 '内包データ': [[{'A':'100','B':'200'}], [{'A':'300', 'B':'400'}]]}) 6 7df2 = df['内包データ'].apply(lambda x: pd.Series(x[0])) 8 9df = pd.concat([df, df2], axis=1) 10

投稿2021/05/01 05:33

bsdfan

総合スコア4794

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pyusr

2021/05/01 06:33

ありがとうございます!無事に実現できました! apply(lambda x: pd.Series(x[0])) これでdictをSeriesに変換、ということになるんですね…applyの使い方覚えようと思います!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問