如何从无序 API 端点获取 pandas DataFrame

作者选择了 自由和开源基金作为 写给捐款计划的一部分接受捐款。

介绍

类似于 Excel 表格或 SQL表,一个 pandas DataFrame是一个两维数据结构,数据以行和列呈现。

使用 Python,您可以将 CSV、Excel 或 API 终端中的数据转换成一个pandas数据框架,然后在获得的数据框架上工作。

有些 API 端点确实存在于字典的阅读友好的格式中,其中密钥代表列名和值代表属于这些列的元素。

在本教程中,您将从未分类的端点获取数据,并以适当的格式呈现给‘panda’ DataFrame。 首先,您将从一些常规 API 格式中提取数据,以便为将分类的 API 数据转换为 DataFrame 提供一些背景。

前提条件

要遵循本教程,您将需要:

对于 Ubuntu 和其他 Linux 发行版,请遵循我们关于 How To Install Python 3 and Set Up a Programming Environment的教程的步骤 1 和 2。对于 macOS,请遵循我们关于 How To Install Python 3 and Set Up a Local Programming Environment on macOS的教程步骤 1-5。对于其他操作系统,请检查 Jupyter Notebook Experience 安装和在您的机器上运行的官方文档。对于运行 Ubuntu/Debian 的远程服务器,请遵循 How to Install, Run, and Connect to Jupyter Notebook on a Remote Server的教程。对于其他操作系统,请检查 [Jupytery 安装的官方文档

步骤 1 – 准备您的Jupyter笔记本环境

对于本教程,您将使用 Jupyter 笔记本与数据一起工作,Jupyter 笔记本对于迭代编码是有用的,因为它允许您写一个小片段的代码,运行它,并返回结果。

要在您的 Jupyter 笔记本中遵循本教程,您需要打开一个新的笔记本并安装所需的依赖,您将在此步骤中完成。

在前提条件下,您在您的服务器上设置了一个Jupyter笔记本环境. 一旦您登录到您的服务器,启用虚拟环境:

1[environment local]
2source ~/environments/my_env/bin/activate

然后运行Jupyter笔记本应用程序来启动应用程序:

1[environment local]
2jupyter notebook

<$>[注] 注: 如果您正在远程服务器上遵循教程,您可以在本地机器的浏览器中使用端口转发访问您的Jupyter笔记本。

打开新终端并输入以下命令:

1[environment local]
2ssh -L 8888:localhost:8888 your_non_root_user@your_server_ip

当您连接到服务器时,请导航到输出提供的链接,以访问您的Jupyter笔记本。

在运行并连接到它后,您将访问基于浏览器的用户界面。从 New下载菜单中,选择 **Python3(ipykernel)**选项,这将打开一个新的卡片,带有未标题的Python笔记本。给您的文件一个名字;在本教程中,该文件被命名为 convert_data.ipynb

然后,在浏览器的Jupyter笔记本的第一个单元格中,使用pip来安装必要的依赖:

1[label convert_data.ipynb]
2pip install pandas
3pip install requests

DataFrame 数据结构只能通过 pandas模块访问,而 requests模块可以帮助您访问 URL。

将命令添加到您的 Jupyter 笔记本后,请按 ** Run** 执行它们。

Jupyter 笔记本将提供一个运行输出,表示依赖性正在下载. 此输出下方将提供一个新的输入单元格,这就是您将运行下一行代码的地方。

接下来,通过运行以下命令导入您刚刚安装的模块:

1[label convert_data.ipynb]
2import pandas as pd
3import requests

「pd」将作为您调用「pandas」模块的捷径,您可以通过只写「pd」来调用「pandas」模块。

在此步骤中,您已经准备了您的 Jupyter 笔记本环境,接下来,您将执行一些基本的转换来从字典创建 DataFrames。

步骤 2 — 将排序的 API 数据转换为pandas数据框架

在从未分类的 API 端点获取数据之前,您首先将从不同格式的字典和在 URL 上组织的 API 数据创建 DataFrames。

在许多 API 终端中,密钥通常代表列名,这些密钥的值代表属于各个列的元素,但是,有些 API 终端并不以这种格式呈现,这意味着您需要一种方法来提取列名及其相应的数据,以创建一个可读的字典,从中可以创建一个panda数据框。

在此步骤中,您将使用一些常见的方法从不同格式的字典创建数据框。

方法 1 – 从字典列表创建数据框架

在此方法中,列表中的每个字典代表了最终数据框架中的数据行. 数据框架结构将包含代表列名称的密钥,其中包含属于列元素的值。

对于此方法,您将创建一个数据框,其中包含列年龄,ID名称,以及三个个人的信息。

在新单元格中,运行以下代码来格式化分配给变量 dict1 的字典列表(请自由用自己的名称替换):

1[label convert_data.ipynb]
2dict1=[{"Age":41,"ID":1234,"Name":"Bella"},{"Age":24,"ID":5678,"Name":"Mark"},{"Age":26,"ID":2341,"Name":"John"}]
3
4data=pd.DataFrame(dict1)
5
6data.head()

您将字典列表分配给dict1变量. 列表中的每个字典代表了结果数据框的单行。 键年龄ID名称代表了列名称。 每个键分配的值代表了该行列的值。 然后您将这个字典传递到pandas模块中,以创建数据框。

以下数据框将打印:

1[secondary_label Output]
2Age	ID	Name
30	41	1234	Bella
41	24	5678	Mark
52	26	2341	John

您在dict1列表中的每个字典中定义的密钥是获得的DataFrame中的列名,而这些字典中的值代表了行式数据。

方法 2 — 从单个字典创建数据框架

在前一种方法中,您根据行定义了数据,从而在列表中输入了多个字典,每个字典代表了行式的数据,其中密钥是列名称,值是属于列的元素。

此时,您将使用一个字典,其密钥代表列名,但其值是代表该列垂直数据的列表。

若要使用此方法,您可以使用在上一节中使用的相同数据,在新单元格中运行以下行:

1[label convert_data.ipynb]
2dict2={"Age":[41,24,26],"ID":[1234,5678,2341],"Name":["Bella","Mark","John"]}
3
4data=pd.DataFrame(dict2)
5
6data.head()

在这里,您可以使用字典定义列式的数据。dict2字典中的密钥是列名称:年龄,ID名称

以下数据框将打印到屏幕上:

1[secondary_label Output]
2Age	ID	Name
30	41	1234	Bella
41	24	5678	Mark
52	26	2341	John

字典dict2中的密钥代表了列名(年龄ID名称),每个列都包含您定义为每个密钥的值的列表,例如年龄列有值41,2426

虽然前两种方法的输出相同,但您可以使用行式和列式方法创建数据框。

方法 3 — 在 URL 上使用 API 数据创建数据框架

在 API 相关的 URL 中,数据通常呈现为类似于方法 1 中使用的数据的字典列表,但而不是硬编码数据,您将使用 requests模块访问 URL 上的 API 数据,这有助于您访问 URL。

对于此方法,您将使用 JSON API 的 URL: Capital Countries,该 URL 以 API 格式列出各国及其首都的列表。

1[environment second]
2https://raw.githubusercontent.com/dariusk/corpora/master/data/geography/countries_with_capitals.json

以下是由 URL 提供的 API 数据的开始部分:

 1[label List of Countries with Capitals (API Data from the Countries with Capitals URL)]
 2[environment second]
 3{
 4  "description": "A list of countries and its respective capitals.",
 5  "countries": [
 6    {"name":"Afghanistan", "capital":"Kabul"},
 7    {"name":"Albania", "capital":"Tirana"},
 8    {"name":"Algeria", "capital":"Algiers"},
 9    {"name":"Andorra", "capital":"Andorra la Vella"},
10    {"name":"Angola", "capital":"Luanda"},
11    {"name":"Antigua & Barbuda", "capital":"St. John's"},
12    {"name":"Argentina", "capital":"Buenos Aires"},
13    {"name":"Armenia", "capital":"Yerevan"},
14    {"name":"Australia", "capital":"Canberra"},
15    {"name":"Austria", "capital":"Vienna"},
16...

API以可识别的格式呈现:外部字典中的国家键包含一份字典列表,其中名称资本是列名,其相应值是行式数据。

若要从此 URL 创建一个pandas数据框,请在新单元格中运行以下代码:

1[label convert_data.ipynb]
2response=requests.get('https://raw.githubusercontent.com/dariusk/corpora/master/data/geography/countries_with_capitals.json').json()
3
4df1=pd.DataFrame(response['countries'])
5
6df1.head()

请求模块允许您获取访问 URL. 在这种情况下,您将 URL 读取为json文件,并将读取数据分配给变量响应。接下来,您将这个词典列表(作为国家键的值提供)呈现给panda,这反过来会提供一个DataFrame。

运行上述代码后,您将收到以下数据框:

1[secondary_label Output]
2         name	        capital
30 Afghanistan Kabul
41 Albania Tirana
52 Algeria Algiers
63 Andorra Andorra la Vella
74 Angola	         Luanda

这是你在将国家和首都列表转移到pandas数据框架后获得的数据框架。当你运行此代码时,你将词典列表(作为国家键的值)转移到pandas数据框架模块中。列名为名称首都,因为它们在该列表中的每个词典中都存在作为密钥,它们的值代表了行式数据(因为每个词典代表一个行)。

到目前为止,您已经从基本字典和结构化 API 终端点创建了 DataFrames。处理包含结构化 API 的 URL 时,数据通常以方法 1 中使用的格式呈现,作为一个字典列表,每个字典代表了行式数据。在API 数据非结构化的情况下,您可以使用方法 1 或 2 中的格式提取列名及其数据,以行式或列式的方式。

步骤 3 — 将无序的 API 数据转换为pandas数据框架

到目前为止,您已经使用多种方法将排序数据转换为pandas数据框,现在您将以不同的格式处理数据,此新 URL 中的 API 数据不是传统格式,因此很难识别列名及其数据。

首先,您将提取列名和所有列的值,然后将列名定义为密钥,列元素(在列表中)作为字典中的值。

此步骤使用来自纽约学校人口统计和问责 snapshot(https://data.cityofnewyork.us/api/views/ihfw-zy9j/rows.json)的数据。

在 API 终端中跟踪列名

在本节中,您将跟踪与 API 终端中包含的数据列相关的信息。

要访问样本数据,请通过您选择的 Web 浏览器打开此 URL:

1[environment second]
2https://data.cityofnewyork.us/api/views/ihfw-zy9j/rows.json

该 URL 中的数据比您在 步骤 2中使用的数据更容易呈现)。 NY Snapshot 数据呈现了一种或另一种形式的字典,但它们不是字典,其中密钥代表列名称,值代表列的元素。

您将首先找到与数据框架列相关的信息,在访问浏览器中的API URL时,请键入CTRL+F并搜索:

 1[environment second]
 2[label The Columns Section (API data from the NY School Snapshot URL)]
 3...
 4"columns" : [ {
 5        "id" : -1,
 6        "name" : "sid",
 7        "dataTypeName" : "meta_data",
 8        "fieldName" : ":sid",
 9        "position" : 0,
10        "renderTypeName" : "meta_data",
11        "format" : { },
12        "flags" : [ "hidden" ]
13      }, {
14        "id" : -1,
15        "name" : "id",
16        "dataTypeName" : "meta_data",
17        "fieldName" : ":id",
18        "position" : 0,
19        "renderTypeName" : "meta_data",
20        "format" : { },
21        "flags" : [ "hidden" ]
22      }, {
23        "id" : -1,
24        "name" : "position",
25        "dataTypeName" : "meta_data",
26        "fieldName" : ":position",
27        "position" : 0,
28        "renderTypeName" : "meta_data",
29        "format" : { },
30        "flags" : [ "hidden" ]
31...

在每个字典中,注意dataTypeName键的值。对于前八个字典,dataTypeName键的值是meta_dataMetadata是描述数据的数据。在这种情况下,元数据不是表中包含的数据,而是描述整个表的数据。因此,这八个字典(包含meta_data作为其dataTypeName键的值)并不代表表中的列信息。

但是,当您继续在这个列表中时,请注意没有meta_data作为值的dataTypeName键的第一个外观:

 1[environment second]
 2[label The Columns Section (API data from the NY School Snapshot URL)]
 3...
 4}, {
 5       "id" : -1,
 6       "name" : "meta",
 7       "dataTypeName" : "meta_data",
 8       "fieldName" : ":meta",
 9       "position" : 0,
10       "renderTypeName" : "meta_data",
11       "format" : { },
12       "flags" : [ "hidden" ]
13     }, {
14       "id" : 45985351,
15       "name" : "DBN",
16       "dataTypeName" : "text",
17       "fieldName" : "dbn",
18       "position" : 1,
19       "renderTypeName" : "text",
20       "tableColumnId" : 8032537,
21       "cachedContents" : {
22         "non_null" : "10075",
23...

具有 45985351 值的词典是第一个没有 meta_data' 作为 dataTypeName' 密钥的值的词典。相反,这个值是 text' 这个词典描述了有关您可能数据集的第一个列的信息。这个词典的元素是 text' 格式(换句话说,字符串)。 这个第一个词典有 DBN' 值为 name' 密钥,表示 DBN' 是您的第一个列的名称。 所有词典(在 columns' 密钥中)跟随这个词典没有 meta_data' 作为数据 TypeName' 密钥的值,表明所有这些词典都代表了您的 DataFrame 下一个列的信息。

现在,您已经了解了如何找到有关表列的信息的基本知识,您将在下一步获取这些列的名称。

查找列名

在本节中,您将从 API 端点添加所有列的名称到名为的列表中,然后将以下行添加到 Jupyter 笔记本中的新单元格中,然后运行该单元格:

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

类似于您在 步骤 2中的方法 3 中所做的,您将通过请求模块阅读此URL中的数据,并将其分配到名为响应的变量中。

在行3中,您定义了列表,而在行5中,您定义了键在视图键的值中,该值反过来又定义在键的值中。

for循环通过附加到键的列表中的每个字典进行迭代,并检查这些字典的dataTypeName键的值。如果当前字典的dataTypeName键的值等于meta_data,则跳过到下一个字典。

接下来,检查列表中的内容,在新单元格中运行下列行:

1[label convert_data.ipynb]
2columns

列名将打印到屏幕上:

 1[secondary_label Output]
 2['DBN',
 3'Name',
 4'schoolyear',
 5'fl_percent',
 6'frl_percent',
 7'total_enrollment',
 8'prek',
 9'k',
10'grade1',
11'grade2',
12'grade3',
13'grade4',
14'grade5',
15'grade6',
16'grade7',
17'grade8',
18'grade9',
19'grade10',
20'grade11',
21'grade12',
22'ell_num',
23'ell_percent',
24'sped_num',
25'sped_percent',
26'ctt_num',
27'selfcontained_num',
28'asian_num',
29'asian_per',
30'black_num',
31'black_per',
32'hispanic_num',
33'hispanic_per',
34'white_num',
35'white_per',
36'male_num',
37'male_per',
38'female_num',
39'female_per']

输出确认任何列的dataTypeName不是meta_data已被添加到列表中。

在本节中,您在未分类的API端点中获得了列表列表,您将需要创建最终的DataFrame。接下来,您将提取属于列表中定义的列表中的数据。

定义一个n次数列表

在本节中,您将确定API中的列数,并定义与此数字相符的子列表列表。

最后,您正在使用 [步骤 2] 的方法 2(https://andsky.com/tech/tutorials/how-to-obtain-a-pandas-dataframe-from-an-unordered-api-endpoint#step-2-converting-ordered-api-data-into-pandas-dataframe)从一个字典中获取一个pandas数据框,其密钥代表列名,而这些密钥的值是代表各列元素的列表。

一旦您使用此操作定义了字典,您将能够通过列表和子列表列表循环动态地对字典进行添加,例如,指数0下的子列表将作为列表中的0列表中的列表名称的元素列表,同样,指数1下的子列表也将作为列表中的1列表名称的元素列表。

在之前的步骤中,您获得了列表列表名称. 现在,您将通过在新单元格中运行此行来检查该列表的长度:

1[label convert_data.ipynb]
2len(columns)

len(列)返回列表中的项目数。

API 中存在的列数将打印到屏幕上:

1[secondary_label Output]
238

由于您有38列,您将定义一个38子列表列表,每个子列表将包含每个列的数据。

在新单元格中运行以下代码,创建38子列表的列表(命名为d):

1[label convert_data.ipynb]
2d = [[] for x in range(len(columns))]
3
4d

要创建列表,请先命名列表(在这种情况下,d)。数据集中的每个数组([])将创建一个新的子列表,其中包含您刚刚找到的 38 列范围中的数据。

下面的输出显示了38子列表的列表:

 1[secondary_label Output]
 2[[],
 3[],
 4[],
 5[],
 6[],
 7[],
 8[],
 9[],
10[],
11[],
12[],
13[],
14[],
15[],
16[],
17[],
18[],
19[],
20[],
21[],
22[],
23[],
24[],
25[],
26[],
27[],
28[],
29[],
30[],
31[],
32[],
33[],
34[],
35[],
36[],
37[],
38[],
39[]]

这些子列表最初是空的,因为您尚未添加任何元素。

您现在在d列表中创建了38子列表,这些38子列表的内容将代表38列的列式数据。

获取列的值

在本节中,您将从 API 终端中提取列式数据,并将该数据附加到您在最后一步创建的38子列表中。

在浏览器中访问 API URL 时,请键入CTRL+F并搜索数据。 将有大约73的发生。

 1[environment second]
 2[label The Data Portion Showing Sublists (API Data from the NY School Snapshot URL)]
 3...
 4"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" ]
 5, [ "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" ]
 6, [ "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" ]
 7, [ "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" ]
 8, [ "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" ]
 9, [ "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" ]
10, [ "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" ]
11...

在分配给数据密钥的列表中,每个子列表都显示了您的潜在数据框的单行值. 要确定实际的行式数据开始的地方,您需要将列数与数据部分的单一子列表中的元素数量进行比较。

通过在新单元格中运行下列行来确认列的数量:

1[label convert_data.ipynb]
2len(columns)

以下输出将打印列的数量:

1[secondary_label Output]
238

接下来,检查数据中的第一个子列表的长度,这是第一个行中的值数:

1[label convert_data.ipynb]
2
3len(response['data'][0])

您在数据中指定第一个子列表,其ID号为0

以下输出将打印数据中的第一个子列表中的元素数目:

1[secondary_label Output]
246

您可能认为,由于数据是行式的,所以第一个子列表(46)中的元素数量将等于列数(38)。然而,每个子列表的长度为 46,这意味着 838多。请记住,您在键中发现了8字典,其中meta_data作为dataTypeName键的值。

由于列表中的索引从0开始,您现在知道这些子列表的值在07范围内(包括)并不代表DataFrame内容,而是代表元数据值。

您将从数据子列表中添加元素,使用循环从索引46-38(8)到索引46。 要测试这一点,您将从第一行中提取数据(而不是从所有子列表中提取所有数据)。

 1[label convert_data.ipynb]
 2count=0
 3
 4for i in response['data'][0][len(response['data'][0])-len(columns):len(response['data'][0])]: #from index 8 to 45
 5
 6    d[count].append(i)
 7
 8    count=count+1
 9
10d

在这种情况下,变量有助于将第一行的列数据附加到d的nth子列表中。

然后,代码通过数据中的第一个子列表进行迭代,以获得从索引8开始的元素,并在索引45结束的元素(结果是38元素)。

「答案(答案)」表示数据键中的第一个子列表的长度,而「len(列)」表示列表的长度,表示最终数据框的列表数量。

以下是发生在前几次迭代中的概述。计数最初为0。当您输入for循环时,iresponse[data][0][8],这是第一个子列表中的第一个非元数据值。

当 i 是 响应[数据] [0][9] (第一个子列表中的第二个非元数据值) 时,你会将 i 值添加到 d[1] (现在的 0 是 1,因为在上一次迭代中, count 被增加到 1 ) 因此,这个值会被添加到列表中的第二个子列表d。

输出显示了第一行数据:

1[secondary_label Output]
2[['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 中的数据键作为值的列表中的第一个子列表进行比较:

1[environment second]
2[label Elements of the First Sublist (API Data from the NY School Snapshot URL)]
3...
4"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" ]
5...

您可能需要向上面的框的右边滚动以查看完整的数据片段。

最初的几个值(从索引 07)代表与元数据列相关的信息. 第一子列表中的突出值(从索引 845)是第一行的值,您已成功提取。

要在所有行中执行相同的任务,您需要更新以前的代码。 首先,在新单元格中运行下列行来重新定义d列表的38子列表:

1[label convert_data.ipynb]
2d = [[] for x in range(len(columns))]

您正在重新定义d列表,因为d子列表列表目前包含第一行中的所有元素,现在您的目标是执行相同的操作,但包括第一行在内的所有剩余行。

现在您已创建一个新的38子列表列表,在新的单元格中运行以下行,该单元格对未来数据框的所有行进行数据提取:

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

在第 1 行中,for i in response[‘data’]意味着i被分配给每个子列表一个接一个。

这里有几个迭代的概述. 您从i开始,列表中的第一个子列表分配给了data键。

在Python中,for循环的上限是专属的,所以你会从索引845的元素。

d[count].append(i[j])的意思是d[0].append(i[8]),意思是你正在将第一个子列表的索引8中的元素附加到列表d的第一个子列表中。

现在4行是d(附加)(i[9]),这意味着第一个子列表的索引9中的元素(仍然按外部循环分配给i)被附加到列表d的第二个子列表中。

在内部循环的末尾,附加第一个行最后一个值的操作将是这样的: d[37].append(i[45]). 在第一个迭代的末尾,列表 d 看起来与之前的输出相同(在所有子列表中的 d 只有一个元素)。

当您突破内部循环时,您将进入外部循环。 i 被分配给数据键分配的列表中的下一个子列表(第二次子列表)。

当您在这个i的第二次迭代中突破内部循环时,所有d的子列表现在将有两个值,每个子列表的第二个值代表属于第二行的数据。

为了让您了解d的子列表中所获得的数据的外观,您将获取d的前三个子列表中的前五个元素,在结果的数据框中,这些值将是前三个列中的前五个元素。

首先,通过对d0索引下次列表的前五个元素进行审查:

1[label convert_data.ipynb]
2d[0][0:5]

输出将显示如下:

1[secondary_label Output]
2['01M015', '01M015', '01M015', '01M015', '01M015']

您可以通过将其与 API 的数据部分进行比较来验证输出,当您在浏览器中查看时:

 1[environment second]
 2[label Elements of the First Sublist (API Data from the NY School Snapshot URL)]
 3...
 4"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" ]
 5, [ "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" ]
 6, [ "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" ]
 7, [ "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" ]
 8, [ "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" ]
 9,
10...

您可能需要向上面的框的右边滚动以查看完整的数据片段。

您获取的值与所突出的值相匹配,这些值在每个子列表的索引8。指数范围中的这些子列表的元素0-7(包括)代表了元数据值,而不是前瞻性数据框的值。

接下来,您可以在d1索引下查看子列表的前五个元素:

1[label convert_data.ipynb]
2d[1][0:5]

第二次子列表的前五个元素将打印到屏幕上:

1[secondary_label Output]
2['P.S. 015 ROBERTO CLEMENTE',
3'P.S. 015 ROBERTO CLEMENTE',
4'P.S. 015 ROBERTO CLEMENTE',
5'P.S. 015 ROBERTO CLEMENTE',
6'P.S. 015 ROBERTO CLEMENTE']

这些值代表列表中的1索引列表中的第五个列表元素:名称

 1[environment second]
 2[label Elements of the Second Sublist (API Data from the NY School Snapshot URL)]
 3...
 4"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" ]
 5, [ "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" ]
 6, [ "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" ]
 7, [ "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" ]
 8, [ "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" ]
 9,
10...

您可能需要向上面的框右转,以查看完整的数据片段. 您获得的值匹配突出值。

最后,审查d的索引2下的子列表的前五个元素:

1[label convert_data.ipynb]
2d[2][0:5]

以下输出将打印到屏幕上:

1[secondary_label Output]
2['20052006', '20062007', '20072008', '20082009', '20092010']

通过 API URL 的数据部分检查输出:

 1[environment second]
 2[label Elements of the Second Sublist (API data from the NY School Snapshot URL)]
 3...
 4"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" ]
 5, [ "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" ]
 6, [ "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" ]
 7, [ "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" ]
 8, [ "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" ]
 9,
10...

您可能需要向上面的框右滚动,以查看完整的数据片段。 您获得的值与所突出的值相匹配. 最终,这些值代表了列表中的2指数列的第五个元素:学年

随着此步骤的结束,您已成功提取所有38列的所有行数据,并将其附加到d列表的38子列表中。

创建一个数据框架的字典

从这个步骤开始,您已经提取了每个38列的名称和值,现在您将将其转移到pandas数据框中,以字典格式。

在新单元格中运行以下代码:

1[label convert_data.ipynb]
2json_dict={}
3
4for i in range(0,len(columns)):
5    json_dict.update({columns[i]:d[i]})

您将通过0到(但不包括)38的范围循环,并将关键值对添加到最终的字典json_dict,您将转移到pandas数据框进行转换,因此,例如,当i0,您将指数0中的d子列表分配为代码DBN,由列[0]表示,并将其转移到剩余的索引。

要想了解字典中获得的密钥将如何看,请查看 `json_dict' 中存在的所有密钥:

1[label convert_data.ipynb]
2json_dict.keys()

最终字典的关键列表将打印到屏幕上:

1[secondary_label Output]
2dict_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'])

d38子列表已被分配到json_dict中的上述38键中,因此,您获得了一个字典,其中关键是列名,值是包含每个列元素的列表。

现在将这个词典转移到pandas来生成一个DataFrame. 这个DataFrame可以用你选择的变量名称命名(本教程使用data):

1[label convert_data.ipynb]
2data=pd.DataFrame(json_dict)

接下来,审查结果数据框架的一部分:

1[label convert_data.ipynb]
2data.head()

DataFrame 的前五行将打印到屏幕上:

1[secondary_label Output]
2DBN	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
30	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
41	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
52	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
63	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
74	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头部

结论

在本教程中,您使用了一些常见的方法来从各种格式的字典和 URL 创建一个pandas数据框,您还创建了一个数据框从 API 终端,其中列和各自的值不会以简单的方式显示。

本教程应该帮助您了解如何使用独特的方法来创建DataFrames,使用从非传统API终端或字典中提取的数据。

Published At
Categories with 技术
comments powered by Disqus