ウェブサイト検索

順不同のAPIエンドポイントからpandas DataFrameを取得する方法


著者は、Write for DOnationsプログラムの一環として寄付を受けるために、Free and Open Source Fundを選びました。

紹介

ExcelのスプレッドシートやSQLテーブルに似て、pandasのDataFrameは、行と列でデータが表示される二次元データ構造です。DataFrameは、科学学習、データサイエンス、機械学習、データ分析などのデータ集中型の分野で主に使用されます。

Pythonを使用すると、CSV、Excel、またはAPIエンドポイントからデータをpandasのDataFrameに変換し、その取得したDataFrameで作業することができます。ExcelおよびCSVファイルの変換は一般的に簡単ですが、APIエンドポイントは異なる場合があるため、その情報からDataFrameを作成するのは難しいことがあります。

いくつかのAPIエンドポイントは、辞書の読みやすい形式で存在し、キーは列名を表し、値はこれらの列に属する要素を表します。ただし、一部のAPIエンドポイントは列名とその値を明確な文脈で表しておらず、無秩序なAPIエンドポイントをDataFrameに変換することは困難な場合があります。

このチュートリアルでは、無秩序なエンドポイントからデータを取得し、それを適切な形式でpandas DataFrameに提示します。まず、いくつかの従来のAPI形式からデータを抽出して、順序付きのAPIデータをDataFrameに変換するためのコンテキストを提供します。その後、無秩序なAPIエンドポイントを扱います。列名とそれぞれの要素を抽出して、辞書を作成します。最後に、この辞書をデータ分析に使用できるpandas DataFrameに渡します。

前提条件

このチュートリアルに従うためには、次のものが必要です:

  • あなたのマシンにPython 3、pip、およびPythonのvenvモジュールがインストールされていることが必要です。Ubuntuや他のLinuxディストリビューションの場合、私たちの「Python 3をインストールし、プログラミング環境を設定する方法」のチュートリアルのステップ1と2に従ってください。macOSの場合は、私たちの「macOSでPython 3をインストールし、ローカルプログラミング環境を設定する方法」のチュートリアルのステップ1~5に従ってください。
  • Jupyterノートブックがあなたのマシンにインストールされ、実行されています。Ubuntu/Debianを実行しているリモートサーバーの場合は、リモートサーバーでJupyterノートブックをインストール、実行、接続する方法を参照してください。他のオペレーティングシステムについては、Jupyterのインストールに関する公式ドキュメントを確認してください。
  • Jupyter Notebookにアクセスするために使用する現代的なウェブブラウザ。
  • Pythonの基本、例えばforループ、関数、データ構造(特にリストと辞書)に対する親しみ。
  • データ操作と分析のためのPythonのpandasモジュールの経験。

ステップ1 — Jupyterノートブック環境の準備

このチュートリアルでは、データを扱うためにJupyter Notebookを使用します。Jupyter Notebookは、少しのコードを記述して実行し、その結果を確認できるため、反復的なコーディングに役立ちます。

このチュートリアルをJupyter Notebookで進めるには、新しいNotebookを開き、必要な依存関係をインストールする必要があります。このステップでそれを行います。

前提条件では、サーバー上にJupyter Notebook環境を設定しました。サーバーにログインしたら、仮想環境をアクティブにしてください:

  1. source ~/environments/my_env/bin/activate

次に、Jupyter Notebookアプリケーションを実行してアプリケーションを開始します:

  1. jupyter notebook

注意: リモートサーバーでチュートリアルを追っている場合は、ポートフォワーディングを使用して、ローカルマシンのブラウザでJupyter Notebookにアクセスできます。

新しいターミナルを開き、次のコマンドを入力してください:

  1. ssh -L 8888:localhost:8888 your_non_root_user@your_server_ip

サーバーに接続したら、出力によって提供されたリンクに移動してJupyter Notebookにアクセスします。この端末は、このチュートリアルの残りの間も開いたままにしてください。

実行して接続した後は、ブラウザベースのユーザーインターフェースにアクセスします。新規ドロップダウンメニューからPython3(ipykernel)オプションを選択すると、新しいタブに名前のないPythonノートブックが開きます。ファイルに名前を付けてください。このチュートリアルでは、ファイル名はconvert_data.ipynbです。

次に、ブラウザのJupyter Notebookの最初のセルで、pipを使用して必要な依存関係をインストールします:

pip install pandas
pip install requests

データフレームのデータ構造は、pandasモジュールを通じてのみアクセス可能です。requestsモジュールは、URLにアクセスするのに役立ちます。

コマンドをJupyter Notebookに追加したら、実行を押してそれらを実行してください。

あなたのJupyterノートブックは、依存関係がダウンロードされていることを示す実行出力を提供します。この出力の下に新しい入力セルが表示され、そこで次のコード行を実行します。

次に、以下のコマンドを実行して、インストールしたモジュールをインポートします:

import pandas as pd
import requests

pdは、pandasモジュールを呼び出すためのショートカットとして機能します。pandasモジュールは、pdと書くだけで呼び出すことができます。

このステップでは、Jupyter Notebook環境を準備しました。次に、辞書からDataFrameを作成するためにいくつかの基本的な変換を実行します。

ステップ2 — 並べられたAPIデータをpandasデータフレームに変換する

無秩序なAPIエンドポイントからデータを取得する前に、まず異なる形式の辞書からデータフレームを作成し、URLにある整理されたAPIデータを作成します。

多くのAPIエンドポイントでは、キーは通常列名を表し、それらのキーの値はそれぞれの列に属する要素を表しています。しかし、一部のAPIエンドポイントはこの形式で提示されていないため、列名とそれに対応するデータを抽出して、pandas DataFrameを作成できる可読な辞書を作る方法が必要になります。従来のAPIエンドポイントをpandas DataFrameに変換するための一般的な手法を確認することで、このタスクに役立つでしょう。

このステップでは、さまざまな形式の辞書からDataFrameを作成するための一般的な方法をいくつか使用します。

方法1 — 辞書のリストからデータフレームを作成する

この方法では、リスト内の各辞書が最終データフレームのデータ行を表します。データフレームの構造には、列名を表すキーが含まれ、列に属する要素の値が含まれます。

この方法では、3人の個人の情報とともに、Age、ID、およびNameという列を持つDataFrameを作成します。

新しいセルで、変数dict1に割り当てられた辞書のリストをフォーマットするために、以下のコードを実行してください(名前は自由に変更して構いません):

dict1=[{"Age":41,"ID":1234,"Name":"Bella"},{"Age":24,"ID":5678,"Name":"Mark"},{"Age":26,"ID":2341,"Name":"John"}]

data=pd.DataFrame(dict1)

data.head()

あなたは辞書のリストをdict1変数に割り当てます。リスト内の各辞書は、結果のDataFrameの単一の行を表します。キーAge、ID、およびNameは列名を表します。各キーに割り当てられた値は、その行のその列の値を示します。その後、この辞書をpandasモジュールに渡してDataFrameを作成します。

次のデータフレームが印刷されます:

Age	ID	Name
0	41	1234	Bella
1	24	5678	Mark
2	26	2341	John

このデータフレームは辞書のリストから作成されました。dict1リスト内の各辞書で定義したキーは、得られたデータフレームの列名であり、これらの辞書の値は行ごとのデータを表しています。

方法2 — 単一の辞書からDataFrameを作成する

前の方法では、データを行に基づいて定義したため、リスト内に複数の辞書をタイプする必要がありました。それぞれの辞書は行ごとのデータを表しており、キーは列名、値は列に属する要素です。

今、あなたはデータを列ごとの形式で定義します。今回は、キーが列名を表し、値がその列の縦のデータを表すリストである辞書を使用します。

この方法を使用するには、前のセクションで使用したのと同じデータを使用できます。新しいセルで以下の行を実行してください:

dict2={"Age":[41,24,26],"ID":[1234,5678,2341],"Name":["Bella","Mark","John"]}

data=pd.DataFrame(dict2)

data.head()

ここでは、辞書を使用して列ごとのデータを定義します。dict2 辞書のキーは列名であり、年齢、ID、および名前です。各キーの値は、各列のデータを表すリストです。

次のデータフレームが画面に表示されます:

Age	ID	Name
0	41	1234	Bella
1	24	5678	Mark
2	26	2341	John

dict2 辞書のキーは列名 (年齢, ID, 名前) を表し、各列は各キーの値として定義したリストで埋められています。例えば、年齢 列には 41, 24, 26 という値があります。

予想通り、両方の方法は同じ結果を生み出します。最初の2つの方法の出力は同じですが、行方向と列方向の両方のアプローチを使用してデータフレームを作成することができます。

方法3 — URLのAPIデータを使用してDataFrameを作成する

この方法では、URLから抽出したAPIデータを含むDataFrameを作成します。API関連のURLでは、データはしばしばMethod 1で使用されたデータに似た辞書のリストとして提示されます。しかし、データをハードコーディングするのではなく、requestsモジュールを使用してURLにあるAPIデータにアクセスします。これにより、URLにアクセスできるようになります。

この方法では、JSON APIのURLを使用します:首都のある国々。これは、API形式で国とその首都のリストを表示します。APIを表示するには、ブラウザで以下のURLにアクセスしてください:

  1. https://raw.githubusercontent.com/dariusk/corpora/master/data/geography/countries_with_capitals.json

これは、URLによって提示されたAPIデータの最初の部分です。

{
  "description": "A list of countries and its respective capitals.",
  "countries": [
    {"name":"Afghanistan", "capital":"Kabul"},
    {"name":"Albania", "capital":"Tirana"},
    {"name":"Algeria", "capital":"Algiers"},
    {"name":"Andorra", "capital":"Andorra la Vella"},
    {"name":"Angola", "capital":"Luanda"},
    {"name":"Antigua & Barbuda", "capital":"St. John's"},
    {"name":"Argentina", "capital":"Buenos Aires"},
    {"name":"Armenia", "capital":"Yerevan"},
    {"name":"Australia", "capital":"Canberra"},
    {"name":"Austria", "capital":"Vienna"},
...

APIは認識可能な形式で提示されています:外部辞書のcountriesキーには、nameとcapitalが列名であり、それに対応する値が行ごとのデータである辞書のリストが含まれています。

このURLからpandas DataFrameを作成するには、新しいセルで次のコードを実行してください:

response=requests.get('https://raw.githubusercontent.com/dariusk/corpora/master/data/geography/countries_with_capitals.json').json()

df1=pd.DataFrame(response['countries'])

df1.head()

requestsモジュールを使用すると、URLにアクセスできます。この場合、URLをjsonファイルとして読み込み、読み取ったデータをresponse変数に割り当てます。次に、countriesキーの値として提供されたこの辞書のリストをpandasに提示し、pandasはDataFrameを提供します。df1は、指定されたAPIエンドポイントからのデータの抽出に成功した場合に得られるDataFrameとなります。

上記のコードを実行すると、以下のデータフレームが得られます:

         name	        capital
0 Afghanistan             Kabul
1     Albania            Tirana
2     Algeria           Algiers
3     Andorra  Andorra la Vella
4      Angola	         Luanda

これは、国と首都のリストをpandas DataFrameに渡した後に得られるDataFrameです。このコードを実行したとき、辞書のリスト(countriesキーの値として示される)をpandas DataFrameモジュールに渡しました。列名はnameとcapitalであり、これらはこのリストのすべての辞書にキーとして存在し、それらの値は行データを表します(各辞書は1行を表します)。

これまで、基本的な辞書と構造化されたAPIエンドポイントからDataFrameを作成してきました。構造化されたAPIを含むURLを扱う場合、データは通常、手法1で使用されている形式で提供されます:各辞書が行データを表す辞書のリストとして。APIデータが非構造的な場合は、手法1または手法2の形式を使用して列名とそのデータを抽出できます:行単位または列単位の方法で。次のステップでは、このステップからのいくつかの戦略を組み合わせて、非構造化APIエンドポイントからデータを取得します。

ステップ3 — 無秩序なAPIデータをpandas DataFrameに変換する

これまで、いくつかの方法を使って順序付きデータをpandasデータフレームに変換してきました。今度は、異なる形式のデータに取り組むことになります。この新しいURLのAPIデータは従来の形式ではなく、列名やそのデータを特定するのが難しくなっています。

この無秩序なデータからデータフレームを作成するためには、追加の手順を踏む必要があります。まず、列名とすべての列の値を抽出し、その後、列名をキー、列要素(リストで)の値を辞書として定義します。最終的には、メソッド2で使用される形式に似た、提示可能な辞書を取得し、それをpandasに提示してデータフレームへの変換を行います。

このステップでは、ニューヨークの学校の人口統計とアカウンタビリティスナップショットからのデータを使用します。

APIエンドポイント内のカラム名の追跡

このセクションでは、APIエンドポイント内に含まれるデータの列に関連する情報を追跡します。

サンプルデータにアクセスするには、お好きなウェブブラウザでこのURLを開いてください:

  1. https://data.cityofnewyork.us/api/views/ihfw-zy9j/rows.json

このURLのデータは、ステップ2で扱ったデータよりも見栄えが良くありません。NY Snapshotデータは、何らかの形の辞書を提示していますが、キーが列名を表し、値が列の要素を表す辞書ではありません。行ごとまたは列ごとのデータを示す直感的な辞書が存在しないようです。

最初に、DataFrame の列に関連する情報を見つけることから始めます。ブラウザで API URL にアクセスする際は、CTRL+F を押して columns を検索してください。

...
"columns" : [ {
        "id" : -1,
        "name" : "sid",
        "dataTypeName" : "meta_data",
        "fieldName" : ":sid",
        "position" : 0,
        "renderTypeName" : "meta_data",
        "format" : { },
        "flags" : [ "hidden" ]
      }, {
        "id" : -1,
        "name" : "id",
        "dataTypeName" : "meta_data",
        "fieldName" : ":id",
        "position" : 0,
        "renderTypeName" : "meta_data",
        "format" : { },
        "flags" : [ "hidden" ]
      }, {
        "id" : -1,
        "name" : "position",
        "dataTypeName" : "meta_data",
        "fieldName" : ":position",
        "position" : 0,
        "renderTypeName" : "meta_data",
        "format" : { },
        "flags" : [ "hidden" ]
...

columnsキーの値リスト内にはいくつかの辞書があります。各辞書内では、dataTypeNameキーの値に注目してください。最初の8つの辞書では、dataTypeNameキーの値はmeta_dataです。メタデータとは、データを説明するデータのことです。この場合、メタデータはテーブル内に含まれるデータではなく、テーブル全体を説明するデータです。したがって、これらの8つの辞書(dataTypeNameキーの値がmeta_dataであるもの)は、テーブル内に存在する列に関する情報を表していません。

ただし、このリストをさらに進めると、値がmeta_dataでない最初のdataTypeNameキーの出現に注意してください:

...
}, {
       "id" : -1,
       "name" : "meta",
       "dataTypeName" : "meta_data",
       "fieldName" : ":meta",
       "position" : 0,
       "renderTypeName" : "meta_data",
       "format" : { },
       "flags" : [ "hidden" ]
     }, {
       "id" : 45985351,
       "name" : "DBN",
       "dataTypeName" : "text",
       "fieldName" : "dbn",
       "position" : 1,
       "renderTypeName" : "text",
       "tableColumnId" : 8032537,
       "cachedContents" : {
         "non_null" : "10075",
...

id に対する値が 45985351 の辞書は、dataTypeName キーに対する値が meta_data でない最初の辞書です。代わりに、その値は text です。この辞書は、最終的なデータセットの最初の列に関する情報を示しています。この列の要素は text 形式(言い換えれば、文字列)です。この最初の辞書には、name キーに対する DBN の値があり、DBN が最初の列の名前であることを示しています。この辞書に続くすべての辞書(columns キー内)は、その dataTypeName キーの値が meta_data ではないため、これらの辞書はすべて、DataFrame の次の列に関する情報を表しています。

テーブルの列に関する情報をどこで見つけるかの基本的な理解ができたので、次のステップではこれらの列の名前を取得します。

列名を探す

このセクションでは、APIエンドポイントからのすべての列の名前をcolumnsというリストに追加します。新しいセルに以下の行を追加し、そのセルを実行してください:

  1. response=requests.get('https://data.cityofnewyork.us/api/views/ihfw-zy9j/rows.json').json()
  2. columns=[]
  3. for i in response['meta']['view']['columns']:
  4. if(i['dataTypeName']=='meta_data'):
  5. continue
  6. else:
  7. columns.append(i['name'])

ステップ2のメソッド3で行ったことと同様に、requestsモジュールを使用してこのURLにあるデータを読み取り、それをresponseという名前の変数に割り当てます。

3行目では、columnsリストを定義しています。5行目では、metaキーの値の中で定義されたviewキーの値の中にcolumnsキーを定義しています。

このforループは、columnsキーに添付されたリスト内のすべての辞書を反復処理し、それらの辞書のdataTypeNameキーの値をチェックします。現在の辞書のdataTypeNameキーの値がmeta_dataに等しい場合、次の辞書にスキップします。そうでない場合は、nameキーの値をcolumnsリストに追加します。

次に、columnsリストの内容を確認します。新しいセルで次の行を実行してください:

columns

列名が画面に印刷されます:

['DBN',
'Name',
'schoolyear',
'fl_percent',
'frl_percent',
'total_enrollment',
'prek',
'k',
'grade1',
'grade2',
'grade3',
'grade4',
'grade5',
'grade6',
'grade7',
'grade8',
'grade9',
'grade10',
'grade11',
'grade12',
'ell_num',
'ell_percent',
'sped_num',
'sped_percent',
'ctt_num',
'selfcontained_num',
'asian_num',
'asian_per',
'black_num',
'black_per',
'hispanic_num',
'hispanic_per',
'white_num',
'white_per',
'male_num',
'male_per',
'female_num',
'female_per']

出力は、dataTypeName が meta_data でない任意の列が columns リストに追加されたことを確認しています。

このセクションでは、無秩序なAPIエンドポイントにある列名のリストを取得しました。これらの列名は最終的なデータフレームを作成するために必要です。次に、columnsリストで定義された列に属するデータを抽出します。

n のサブリストのリストを定義する

このセクションでは、APIの列数を決定し、この数に対応するサブリストのリストを定義します。

最終的には、あなたはステップ2のメソッド2を使用して、列名を表すキーを持ち、そのキーの値がそれぞれの列の要素を表すリストである辞書からpandasのDataFrameを取得していることになります。APIで列の数を特定した後、同じ数のサブリストのリストを定義し、各サブリストにはそれぞれの列のデータが含まれます。

この操作を使用して辞書を定義すると、columnsリストとサブリストのリストをループすることで、辞書に動的に追加することができます。たとえば、インデックス0のサブリストは、columnsリストのインデックス0の列名に対する要素のリストとして機能します。同様に、インデックス1のサブリストは、columnsリストのインデックス1の列名に対する要素のリストとして機能します。

前のステップで、列名のリストを取得しました。今、あなたは新しいセルでこの行を実行することで、このリストの長さを確認します:

len(columns)

len(columns)はcolumnsリスト内のアイテムの数を返します。

APIに存在する列の数が画面に出力されます:

38

あなたには38列があるので、各列のデータを含む38のサブリストのリストを定義します。

以下のコードを新しいセルで実行して、38のサブリストのリスト(名前はd)を作成してください。

d = [[] for x in  range(len(columns))]

d

リストを作成するには、まずそれに名前を付けます(この場合は、d)。データセットの各配列([])は、あなたが見つけた38列の範囲からのデータを含む新しいサブリストを作成します。

以下の出力は、38個のサブリストのリストを示しています。

[[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[]]

これらのサブリストは、まだ要素を追加していないため、最初は空です。

あなたは現在、リストd内に38のサブリストを作成しました。これらの38のサブリストの内容は、38の列の列方向のデータを表します。その内容を次に追加します。

列の値を取得する

このセクションでは、APIエンドポイントから列ごとのデータを抽出し、そのデータを前のステップで作成した38のサブリストに追加します。そのためには、最初にAPI全体のどこにdataキーが存在するかを見つける必要があります。dataキーの値は、テーブルの内容を表します。

ブラウザでAPI URLにアクセスする際、CTRL+Fを押してdataを検索してください。約73回の出現があるはずです。最後の出現を見つけると、次のような情報が表示されます:

...
"data" : [ [ "row-h6zp~rx75.iwiv", "00000000-0000-0000-C205-81EF0C7F0969", 0, 1425758466, null, 1425758466, null, "{ }", "01M015", "P.S. 015 ROBERTO CLEMENTE", "20052006", "89.4", null, "281", "15", "36", "40", "33", "38", "52", "29", "38", null, null, null, null, null, null, "36", "12.8", "57", "20.3", "25", "9", "10", "3.6", "74", "26.3", "189", "67.3", "5", "1.8", "158", "56.2", "123", "43.8" ]
, [ "row-bgbf_ntuw.ckdq", "00000000-0000-0000-9AF5-4D58BAF51C20", 0, 1425758466, null, 1425758466, null, "{ }", "01M015", "P.S. 015 ROBERTO CLEMENTE", "20062007", "89.4", null, "243", "15", "29", "39", "38", "34", "42", "46", null, null, null, null, null, null, null, "38", "15.6", "55", "22.6", "19", "15", "18", "7.4", "68", "28", "153", "63", "4", "1.6", "140", "57.6", "103", "42.4" ]
, [ "row-mspc-8wz5_uxb8", "00000000-0000-0000-9E11-73B99A1B02D9", 0, 1425758466, null, 1425758466, null, "{ }", "01M015", "P.S. 015 ROBERTO CLEMENTE", "20072008", "89.4", null, "261", "18", "43", "39", "36", "38", "47", "40", null, null, null, null, null, null, null, "52", "19.9", "60", "23", "20", "14", "16", "6.1", "77", "29.5", "157", "60.2", "7", "2.7", "143", "54.8", "118", "45.2" ]
, [ "row-p6za~9ikt~ums7", "00000000-0000-0000-D2CD-5904BA5DC16E", 0, 1425758466, null, 1425758466, null, "{ }", "01M015", "P.S. 015 ROBERTO CLEMENTE", "20082009", "89.4", null, "252", "17", "37", "44", "32", "34", "39", "49", null, null, null, null, null, null, null, "48", "19", "62", "24.6", "21", "17", "16", "6.3", "75", "29.8", "149", "59.1", "7", "2.8", "149", "59.1", "103", "40.9" ]
, [ "row-55ss_ktcg~w7ru", "00000000-0000-0000-9425-35118FA9200F", 0, 1425758466, null, 1425758466, null, "{ }", "01M015", "P.S. 015 ROBERTO CLEMENTE", "20092010", "   ", "96.5", "208", "16", "40", "28", "32", "30", "24", "38", null, null, null, null, null, null, null, "40", "19.2", "46", "22.1", "14", "14", "16", "7.7", "67", "32.2", "118", "56.7", "6", "2.9", "124", "59.6", "84", "40.4" ]
, [ "row-ugmn-sxmy_fyiu", "00000000-0000-0000-2070-ABC0343F1148", 0, 1425758466, null, 1425758466, null, "{ }", "01M015", "P.S. 015 ROBERTO CLEMENTE", "20102011", "   ", "96.5", "203", "13", "37", "35", "33", "30", "30", "25", null, null, null, null, null, null, null, "30", "14.8", "46", "22.7", "21", "9", "13", "6.4", "75", "36.9", "110", "54.2", "4", "2", "113", "55.7", "90", "44.3" ]
, [ "row-a4rf-xqy7~fvkh", "00000000-0000-0000-AF7F-41FA5EB8E91E", 0, 1425758466, null, 1425758466, null, "{ }", "01M015", "P.S. 015 ROBERTO CLEMENTE                       ", "20112012", null, "89.4", "189", "13", "31", "35", "28", "25", "28", "29", "    ", "    ", "    ", "    ", "    ", "    ", "    ", "20", "10.6", "40", "21.2", "23", "7", "12", "6.3", "63", "33.3", "109", "57.7", "4", "2.1", "97", "51.3", "92", "48.7" ]
...

リスト内の各サブリストは、dataキーに割り当てられた値が、あなたの期待されるデータフレームの単一行を示します。実際の行データがどこから始まるかを判断するには、列の数をdataセクションの単一サブリスト内の要素の数と比較する必要があります。

新しいセルで次の行を実行して、列の数を確認してください:

len(columns)

次の出力は、列の数を印刷します:

38

次に、data内の最初のサブリストの長さを確認します。これは最初の行の値の数です。

len(response['data'][0])

あなたはdataの最初のサブリストをそのID番号0で指定します。

以下の出力は、dataの最初のサブリスト内の要素の数を印刷します:

46

データが行単位であるため、最初のサブリストの要素数(46)が列数(38)に等しいと思うかもしれません。しかし、各サブリストの長さは46であり、これは38よりも8多いです。columnsキーの中で、dataTypeNameキーの値としてmeta_dataを持つ8つの辞書を見つけたことを思い出してください。したがって、これらのサブリストの最初にある余分な8の値はメタデータの値を示しており、テーブルの内容を表しているわけではありません。

リストのインデックスは 0 から始まるため、今、これらのサブリストの 0 から 7(含む)の範囲の値が DataFrame の内容を表していないことを理解しましたが、メタデータの値を表しています。したがって、行データの内容はインデックス 8 から始まります。

あなたは、インデックス 46-38 (8) からインデックス 46 までのループを使って、data サブリスト内の要素を追加します。これを試すために、最初の行からデータを抽出します(すべてのサブリストからすべてのデータを抽出するのではなく)。新しいセルで次の行を実行してください:

count=0

for i in response['data'][0][len(response['data'][0])-len(columns):len(response['data'][0])]: #from index 8 to 45

    d[count].append(i)

    count=count+1

d

この場合、変数countは、最初の行の列データをdのn番目のサブリストに追加するのに役立ちます。

その後、コードはdata内の最初のサブリストを繰り返し、インデックス8からインデックス45までの要素を取得します(これにより38個の要素が得られます)。

length(response['data'][0])は、dataキー内の最初のサブリストの長さを表し、len(columns)はリストcolumnsの長さ、最終的なDataFrameの列の数を示します。

以下は最初の数回の反復で何が起こるかの概要です。カウントは最初は0です。forループに入ると、iはresponse['data'][0][8]、最初のサブリスト内の最初の非メタデータ値になります。このiの値をd[0]に追加します; 括弧内の0は現在のカウント値です。結果として、この値がリストdの最初のサブリストに追加されます。

カウントは1ずつ増加します。iがresponse['data'][0][9](最初のサブリスト内の2番目の非メタデータ値)であるとき、iの値をd[1]に追加します(0は、前の反復でcountが1ずつ増加したため、現在は1です)。その結果、この値はリストd内の2番目のサブリストに追加されます。このプロセスはインデックス45に到達するまで続きます。上記のコードの最後の行は、更新されたdのサブリストのリストを表示します。

出力には最初の行のデータが表示されます。

[['01M015'], ['P.S. 015 ROBERTO CLEMENTE'], ['20052006'], ['89.4'], [None], ['281'], ['15'], ['36'], ['40'], ['33'], ['38'], ['52'], ['29'], ['38'], [None], [None], [None], [None], [None], [None], ['36'], ['12.8'], ['57'], ['20.3'], ['25'], ['9'], ['10'], ['3.6'], ['74'], ['26.3'], ['189'], ['67.3'], ['5'], ['1.8'], ['158'], ['56.2'], ['123'], ['43.8']]

最初の行が正しいデータを含んでいるか確認するために、それをAPI URLのキーの値として使用されているリスト内の最初のサブリストと比較してください。

...
"data" : [ [ "row-h6zp~rx75.iwiv", "00000000-0000-0000-C205-81EF0C7F0969", 0, 1425758466, null, 1425758466, null, "{ }", "01M015", "P.S. 015 ROBERTO CLEMENTE", "20052006", "89.4", null, "281", "15", "36", "40", "33", "38", "52", "29", "38", null, null, null, null, null, null, "36", "12.8", "57", "20.3", "25", "9", "10", "3.6", "74", "26.3", "189", "67.3", "5", "1.8", "158", "56.2", "123", "43.8" ]
...

上のボックスの右にスクロールする必要があるかもしれません。完全なデータスニペットを見るためです。

最初のいくつかの値(インデックス0から7まで)は、メタデータ列に関連する情報を表しています。最初のサブリスト内の強調表示された値(インデックス8から45まで)は、あなたが成功裏に抽出した最初の行の値です。

すべての行に対して同じ作業を実行するには、以前のコードを更新する必要があります。まず、新しいセルで次の行を実行して、dのリストを38のサブリストで再定義します。

d = [[] for x in  range(len(columns))]

あなたはdリストを再定義しています、なぜならサブリストのリストdには現在、最初の行のすべての要素が含まれているからです。今、あなたの目標は、最初の行を含むすべての残りの行に対して同じ操作を行うことです。

新しい 38 のサブリストを作成したので、新しいセルで以下の行を実行してください。これは、期待されるデータフレームのすべての行のデータ抽出を行います:

  1. for i in response['data']:
  2. count=0
  3. for j in range(len(response['data'][0])-len(columns),len(response['data'][0])):
  4. d[count].append(i[j])
  5. count+=1

行1では、for i in response['data']は、iがサブリストのそれぞれに一つずつ割り当てられていることを意味します。

いくつかのイテレーションの概略を示します。最初に、dataキーにリスト内の最初のサブリストが割り当てられた状態でが始まります。カウントは0です。

行3は、すべてのサブリストのインデックス8から46までの要素を反復処理することを可能にします。Pythonでは、forループの上限は排他的なので、インデックス8から45までの要素を取得することになります。

d[count].append(i[j])はd[0].append(i[8])を意味し、これは最初のサブリスト(現在iに割り当てられている)におけるインデックス8の要素をリストdの最初のサブリストに追加していることを意味します。countは1だけ増加します。引き続き内側のループにいます。jは今9です。

行4は現在d[1].append(i[9])です。これは、最初のサブリストのインデックス9にある要素(外側のループに従ってiにまだ割り当てられている)が、リストdの2番目のサブリストに追加されることを意味します。countがインクリメントされます。内側のループは、単一の行のすべての値をすべてのサブリストに追加し終わるまで続きます。

内側のループの最後で、最初の行の最後の値を追加する操作は次のようになります: d[37].append(i[45])。iの最初の反復の最後で、リストdは前の出力と同じように見えます(dのすべてのサブリストに1つの要素しか含まれていません)。

内部ループを抜け出すと、外部ループに移ります。iは、dataキーに割り当てられたリスト内の次のサブリスト(2番目のサブリスト)に割り当てられます。カウント値は現在0に戻っています。

この二回目の i の反復で内部ループを抜けると、d のすべてのサブリストにはそれぞれ二つの値が含まれるようになります。各サブリストの二つ目の値は、二行目に属するデータを表します。このプロセスは、data キーに割り当てられたリスト内のすべてのサブリストに対して続きます。

得られたデータがdのサブリストにどのように見えるかを示すために、dの最初の3つのサブリストの最初の5つの要素を取得します。その結果のデータフレームでは、これらの値が最初の3つの列の最初の5つの要素になります。

まず、dのインデックス0にあるサブリストの最初の5つの要素を確認してください:

d[0][0:5]

出力には次の内容が表示されます:

['01M015', '01M015', '01M015', '01M015', '01M015']

ブラウザで見たときにAPIのdataセクションと比較することで出力を確認できます:

...
"data" : [ [ "row-h6zp~rx75.iwiv", "00000000-0000-0000-C205-81EF0C7F0969", 0, 1425758466, null, 1425758466, null, "{ }", "01M015", "P.S. 015 ROBERTO CLEMENTE", "20052006", "89.4", null, "281", "15", "36", "40", "33", "38", "52", "29", "38", null, null, null, null, null, null, "36", "12.8", "57", "20.3", "25", "9", "10", "3.6", "74", "26.3", "189", "67.3", "5", "1.8", "158", "56.2", "123", "43.8" ]
, [ "row-bgbf_ntuw.ckdq", "00000000-0000-0000-9AF5-4D58BAF51C20", 0, 1425758466, null, 1425758466, null, "{ }", "01M015", "P.S. 015 ROBERTO CLEMENTE", "20062007", "89.4", null, "243", "15", "29", "39", "38", "34", "42", "46", null, null, null, null, null, null, null, "38", "15.6", "55", "22.6", "19", "15", "18", "7.4", "68", "28", "153", "63", "4", "1.6", "140", "57.6", "103", "42.4" ]
, [ "row-mspc-8wz5_uxb8", "00000000-0000-0000-9E11-73B99A1B02D9", 0, 1425758466, null, 1425758466, null, "{ }", "01M015", "P.S. 015 ROBERTO CLEMENTE", "20072008", "89.4", null, "261", "18", "43", "39", "36", "38", "47", "40", null, null, null, null, null, null, null, "52", "19.9", "60", "23", "20", "14", "16", "6.1", "77", "29.5", "157", "60.2", "7", "2.7", "143", "54.8", "118", "45.2" ]
, [ "row-p6za~9ikt~ums7", "00000000-0000-0000-D2CD-5904BA5DC16E", 0, 1425758466, null, 1425758466, null, "{ }", "01M015", "P.S. 015 ROBERTO CLEMENTE", "20082009", "89.4", null, "252", "17", "37", "44", "32", "34", "39", "49", null, null, null, null, null, null, null, "48", "19", "62", "24.6", "21", "17", "16", "6.3", "75", "29.8", "149", "59.1", "7", "2.8", "149", "59.1", "103", "40.9" ]
, [ "row-55ss_ktcg~w7ru", "00000000-0000-0000-9425-35118FA9200F", 0, 1425758466, null, 1425758466, null, "{ }", "01M015", "P.S. 015 ROBERTO CLEMENTE", "20092010", "   ", "96.5", "208", "16", "40", "28", "32", "30", "24", "38", null, null, null, null, null, null, null, "40", "19.2", "46", "22.1", "14", "14", "16", "7.7", "67", "32.2", "118", "56.7", "6", "2.9", "124", "59.6", "84", "40.4" ]
,
...

上のボックスの右にスクロールする必要があるかもしれません。完全なデータスニペットを見るためです。

あなたが得た値は、各サブリストのインデックス8にあるハイライトされた値と一致しています。これらのサブリストのインデックス範囲0-7(含む)の要素は、将来のDataFrameの値ではなく、メタデータの値を表しています。最終的に、これらの値はcolumnsのインデックス0の列の最初の5つの要素を表します。

次に、dのインデックス1のサブリストの最初の5つの要素を確認できます:

d[1][0:5]

第二のサブリストの最初の5つの要素が画面に表示されます。

['P.S. 015 ROBERTO CLEMENTE',
'P.S. 015 ROBERTO CLEMENTE',
'P.S. 015 ROBERTO CLEMENTE',
'P.S. 015 ROBERTO CLEMENTE',
'P.S. 015 ROBERTO CLEMENTE']

これらの値は、columnsリストのインデックス1にある列の最初の5つの要素を表しています: Name。出力をAPI URLのdataセクションで確認してください:

...
"data" : [ [ "row-h6zp~rx75.iwiv", "00000000-0000-0000-C205-81EF0C7F0969", 0, 1425758466, null, 1425758466, null, "{ }", "01M015", "P.S. 015 ROBERTO CLEMENTE", "20052006", "89.4", null, "281", "15", "36", "40", "33", "38", "52", "29", "38", null, null, null, null, null, null, "36", "12.8", "57", "20.3", "25", "9", "10", "3.6", "74", "26.3", "189", "67.3", "5", "1.8", "158", "56.2", "123", "43.8" ]
, [ "row-bgbf_ntuw.ckdq", "00000000-0000-0000-9AF5-4D58BAF51C20", 0, 1425758466, null, 1425758466, null, "{ }", "01M015", "P.S. 015 ROBERTO CLEMENTE", "20062007", "89.4", null, "243", "15", "29", "39", "38", "34", "42", "46", null, null, null, null, null, null, null, "38", "15.6", "55", "22.6", "19", "15", "18", "7.4", "68", "28", "153", "63", "4", "1.6", "140", "57.6", "103", "42.4" ]
, [ "row-mspc-8wz5_uxb8", "00000000-0000-0000-9E11-73B99A1B02D9", 0, 1425758466, null, 1425758466, null, "{ }", "01M015", "P.S. 015 ROBERTO CLEMENTE", "20072008", "89.4", null, "261", "18", "43", "39", "36", "38", "47", "40", null, null, null, null, null, null, null, "52", "19.9", "60", "23", "20", "14", "16", "6.1", "77", "29.5", "157", "60.2", "7", "2.7", "143", "54.8", "118", "45.2" ]
, [ "row-p6za~9ikt~ums7", "00000000-0000-0000-D2CD-5904BA5DC16E", 0, 1425758466, null, 1425758466, null, "{ }", "01M015", "P.S. 015 ROBERTO CLEMENTE", "20082009", "89.4", null, "252", "17", "37", "44", "32", "34", "39", "49", null, null, null, null, null, null, null, "48", "19", "62", "24.6", "21", "17", "16", "6.3", "75", "29.8", "149", "59.1", "7", "2.8", "149", "59.1", "103", "40.9" ]
, [ "row-55ss_ktcg~w7ru", "00000000-0000-0000-9425-35118FA9200F", 0, 1425758466, null, 1425758466, null, "{ }", "01M015", "P.S. 015 ROBERTO CLEMENTE", "20092010", "   ", "96.5", "208", "16", "40", "28", "32", "30", "24", "38", null, null, null, null, null, null, null, "40", "19.2", "46", "22.1", "14", "14", "16", "7.7", "67", "32.2", "118", "56.7", "6", "2.9", "124", "59.6", "84", "40.4" ]
,
...

上のボックスの右側にスクロールする必要があるかもしれません。取得した値は、ハイライトされた値と一致しています。

最後に、dのインデックス2にあるサブリストの最初の5つの要素を確認してください:

d[2][0:5]

次の出力が画面に表示されます:

['20052006', '20062007', '20072008', '20082009', '20092010']

API URLのdataセクションで出力を確認してください。

...
"data" : [ [ "row-h6zp~rx75.iwiv", "00000000-0000-0000-C205-81EF0C7F0969", 0, 1425758466, null, 1425758466, null, "{ }", "01M015", "P.S. 015 ROBERTO CLEMENTE", "20052006", "89.4", null, "281", "15", "36", "40", "33", "38", "52", "29", "38", null, null, null, null, null, null, "36", "12.8", "57", "20.3", "25", "9", "10", "3.6", "74", "26.3", "189", "67.3", "5", "1.8", "158", "56.2", "123", "43.8" ]
, [ "row-bgbf_ntuw.ckdq", "00000000-0000-0000-9AF5-4D58BAF51C20", 0, 1425758466, null, 1425758466, null, "{ }", "01M015", "P.S. 015 ROBERTO CLEMENTE", "20062007", "89.4", null, "243", "15", "29", "39", "38", "34", "42", "46", null, null, null, null, null, null, null, "38", "15.6", "55", "22.6", "19", "15", "18", "7.4", "68", "28", "153", "63", "4", "1.6", "140", "57.6", "103", "42.4" ]
, [ "row-mspc-8wz5_uxb8", "00000000-0000-0000-9E11-73B99A1B02D9", 0, 1425758466, null, 1425758466, null, "{ }", "01M015", "P.S. 015 ROBERTO CLEMENTE", "20072008", "89.4", null, "261", "18", "43", "39", "36", "38", "47", "40", null, null, null, null, null, null, null, "52", "19.9", "60", "23", "20", "14", "16", "6.1", "77", "29.5", "157", "60.2", "7", "2.7", "143", "54.8", "118", "45.2" ]
, [ "row-p6za~9ikt~ums7", "00000000-0000-0000-D2CD-5904BA5DC16E", 0, 1425758466, null, 1425758466, null, "{ }", "01M015", "P.S. 015 ROBERTO CLEMENTE", "20082009", "89.4", null, "252", "17", "37", "44", "32", "34", "39", "49", null, null, null, null, null, null, null, "48", "19", "62", "24.6", "21", "17", "16", "6.3", "75", "29.8", "149", "59.1", "7", "2.8", "149", "59.1", "103", "40.9" ]
, [ "row-55ss_ktcg~w7ru", "00000000-0000-0000-9425-35118FA9200F", 0, 1425758466, null, 1425758466, null, "{ }", "01M015", "P.S. 015 ROBERTO CLEMENTE", "20092010", "   ", "96.5", "208", "16", "40", "28", "32", "30", "24", "38", null, null, null, null, null, null, null, "40", "19.2", "46", "22.1", "14", "14", "16", "7.7", "67", "32.2", "118", "56.7", "6", "2.9", "124", "59.6", "84", "40.4" ]
,
...

上のボックスの右側にスクロールする必要があるかもしれません、完全なデータスニペットを表示するために。取得した値は強調表示された値と一致します。最終的に、これらの値はcolumnsリストのインデックス2の列の最初の5つの要素を表します:schoolyear。

このステップの終わりに達すると、すべての 38 列のすべての行のデータを正常に抽出し、それらをリスト d の 38 のサブリストに追加しました。これで、これまでに得られたデータから pandas データフレームを作成するための最終ステップの準備が整いました。

データフレーム用の辞書を作成する

このステップでは、38の列それぞれの名前と値を抽出しました。それらを今から辞書形式でpandasのDataFrameに渡します。このセクションでは、列名(columnsのリストから取得したもの)をキーとし、値としてdから取得した38のサブリストを持つ辞書を作成します。

新しいセルで次のコードを実行してください:

json_dict={}

for i in  range(0,len(columns)):
	json_dict.update({columns[i]:d[i]})

0から38未満の範囲をループし、最終的な辞書json_dictにキーと値のペアを追加します。これは、pandasのDataFrameに渡して変換します。つまり、例えば、iが0のとき、dのインデックス0にあるサブリストをキーDBN(columns[0]で表される)の値として割り当て、残りのインデックスも同様に続きます。

辞書から得られたキーがどのように見えるかを理解するために、json_dict に存在するすべてのキーを確認してください。

json_dict.keys()

最終辞書のキーのリストが画面に表示されます:

dict_keys(['DBN', 'Name', 'schoolyear', 'fl_percent', 'frl_percent', 'total_enrollment', 'prek', 'k', 'grade1', 'grade2', 'grade3', 'grade4', 'grade5', 'grade6', 'grade7', 'grade8', 'grade9', 'grade10', 'grade11', 'grade12', 'ell_num', 'ell_percent', 'sped_num', 'sped_percent', 'ctt_num', 'selfcontained_num', 'asian_num', 'asian_per', 'black_num', 'black_per', 'hispanic_num', 'hispanic_per', 'white_num', 'white_per', 'male_num', 'male_per', 'female_num', 'female_per'])

dの38のサブリストは、上記のjson_dictの38のキーに割り当てられています。したがって、キーが列名で、値が各列の要素を含むリストの辞書を取得しました。

この辞書を pandas に渡して、DataFrame を生成します。この DataFrame は、任意の変数名で呼び出すことができます(このチュートリアルでは data を使用しています):

data=pd.DataFrame(json_dict)

次に、得られたデータフレームの一部をレビューします:

data.head()

データフレームの最初の5行が画面に表示されます:

DBN	Name	schoolyear	fl_percent	frl_percent	total_enrollment	prek	k	grade1	grade2	...	black_num	black_per	hispanic_num	hispanic_per	white_num	white_per	male_num	male_per	female_num	female_per
0	01M015	P.S. 015 ROBERTO CLEMENTE	20052006	89.4	None	281	15	36	40	33	...	74	26.3	189	67.3	5	1.8	158	56.2	123	43.8
1	01M015	P.S. 015 ROBERTO CLEMENTE	20062007	89.4	None	243	15	29	39	38	...	68	28	153	63	4	1.6	140	57.6	103	42.4
2	01M015	P.S. 015 ROBERTO CLEMENTE	20072008	89.4	None	261	18	43	39	36	...	77	29.5	157	60.2	7	2.7	143	54.8	118	45.2
3	01M015	P.S. 015 ROBERTO CLEMENTE	20082009	89.4	None	252	17	37	44	32	...	75	29.8	149	59.1	7	2.8	149	59.1	103	40.9
4	01M015	P.S. 015 ROBERTO CLEMENTE	20092010		96.5	208	16	40	28	32	...	67	32.2	118	56.7	6	2.9	124	59.6	84	40.4

上のボックスの右側にスクロールして、完全なDataFrame headを表示する必要があるかもしれません。URLから抽出したデータを渡すことで、DataFrameを正常に作成しました。

結論

このチュートリアルでは、さまざまな形式の辞書やURLからデータフレームを作成するための一般的な方法をいくつか使用しました。また、列とそれらの対応する値が明確には表示されていないAPIエンドポイントからデータフレームも作成しました。

このチュートリアルは、従来のAPIエンドポイントや辞書から抽出したデータを使用してユニークな方法でDataFrameを作成する方法を理解するのに役立つはずです。pandas DataFrameについての詳細は、私たちのpandasチュートリアルをチェックしてください。

関連記事: