如何加载 Plaid banking API 对 python 中的 pandas 数据框的响应?
How can I load a Plaid banking API response to a pandas dataframe in python?
我正在使用 Plaid 的 API 至 return 银行账户余额。他们的文档表明所有响应都是标准的 JSON。我有从请求模块加载 JSON 响应的经验,但我无法直接将 Plaid 的响应加载到 pandas 数据帧。这是我尝试时发生的情况:
request = AccountsBalanceGetRequest(access_token=token)
response = client.accounts_balance_get(request)
df = pd.json_normalize(response, record_path=['accounts'])
ERROR:
File "C:\Users\<me>\AppData\Local\Programs\Python\Python39\lib\site-packages\pandas\io\json\_normalize.py", line 423, in _json_normalize
raise NotImplementedError
作为参考,print(response['accounts']) 正确访问了响应的相关部分。这是错误中的 _normalize 部分,但我不明白如何应用它来解决问题:
if isinstance(data, list) and not data:
return DataFrame()
elif isinstance(data, dict):
# A bit of a hackjob
data = [data]
elif isinstance(data, abc.Iterable) and not isinstance(data, str):
# GH35923 Fix pd.json_normalize to not skip the first element of a
# generator input
data = list(data)
else:
raise NotImplementedError
如果我打印响应,它看起来像这样:
{'accounts': [{'account_id': 'account_1',
'balances': {'available': 300.0,
'current': 300.0,
'iso_currency_code': 'USD',
'limit': None,
'unofficial_currency_code': None},
'mask': 'xxx1',
'name': 'SAVINGS',
'official_name': 'Bank Savings',
'subtype': 'savings',
'type': 'depository'},
{'account_id': 'account_2',
'balances': {'available': 500.00,
'current': 600.0,
'iso_currency_code': 'USD',
'limit': None,
'unofficial_currency_code': None},
'mask': 'xxx2',
'name': 'CHECKING',
'official_name': 'Bank Checking',
'subtype': 'checking',
'type': 'depository'},
{'account_id': 'account_3',
'balances': {'available': 2000.00,
'current': 2000.00,
'iso_currency_code': 'USD',
'limit': None,
'unofficial_currency_code': None},
'mask': 'xxx3',
'name': 'BUSINESS CHECKING',
'official_name': 'Bank Business Checking',
'subtype': 'checking',
'type': 'depository'}],
'item': {'available_products': ['balance'],
'billed_products': ['auth', 'transactions'],
'consent_expiration_time': None,
'error': None,
'institution_id': 'ins_123xyz',
'item_id': 'item_123xyz',
'update_type': 'background',
'webhook': ''},
'request_id': 'request_123xyz'}
我假设如果 Plaid 的响应是标准的 JSON,单引号只在那里,因为 Python 的打印将它们从双引号转换而来。如果我将这个字符串作为基础并将单引号替换为双引号,并将 None 替换为 "None" ,我可以加载到数据框:
data = json.loads(responseString.replace("'", '"').replace('None', '"None"'))
df = pd.json_normalize(data, record_path=['accounts'])
print(df)
将此直接应用于 Plaid 的响应也有效:
data = str(response)
data = data.replace("'", '"').replace('None', '"None"')
data = json.loads(data)
df = pd.json_normalize(data, record_path=['accounts'])
我所拥有的似乎是一个临时的解决方法,但不是一个可靠的或预期的解决方案。有没有更好的到达方式?
更新 1:此 post 中第一个代码块的预期输出将产生以下数据帧,而不是错误:
account_id mask name official_name subtype ... balances.available balances.current balances.iso_currency_code balances.limit balances.unofficial_currency_code
0 account_1 xxx1 SAVINGS Bank Savings savings ... 300.0 300.0 USD None None
1 account_2 xxx2 CHECKING Bank Checking checking ... 500.0 600.0 USD None None
2 account_3 xxx3 BUSINESS CHECKING Bank Business Checking checking ... 2000.0 2000.0 USD None None
我可以通过解决方法获得相同的输出,但不明白为什么它是必要的,而且依靠用双引号替换单引号似乎不是获得结果的好方法。
更新 2:我在 2021 年 10 月 15 日使用非 docker 说明和 npm 安装了格子组件。
print(plaid.__version__)
8.2.0
$ py --version
Python 3.9.6
更新 3:根据 Stephen 建议的答案添加完整的解决方案。响应需要首先显式转换为字典,然后从那里进行处理。什么有效:
json_string = json.loads(json.dumps(response.to_dict()))
df = pd.json_normalize(json_string, record_path=['accounts'])
这让我可以省去转换为字符串后所需的所有变通方法,基本上直接加载到数据帧。
所以我认为解决方案是这样的
json_string = json.dumps(response.to_dict())
# which you can then input into a df
基本上,我们从 API 返回字典转移到返回 Python 模型。所以我们需要从 model
-> dictionary
-> json
旅行。 to_dict
是每个输出字典的模型上的方法,然后 json.dumps
接收字典并将其转换为有效的 JSON.
LMK 如果这对你有用:)
我正在使用 Plaid 的 API 至 return 银行账户余额。他们的文档表明所有响应都是标准的 JSON。我有从请求模块加载 JSON 响应的经验,但我无法直接将 Plaid 的响应加载到 pandas 数据帧。这是我尝试时发生的情况:
request = AccountsBalanceGetRequest(access_token=token)
response = client.accounts_balance_get(request)
df = pd.json_normalize(response, record_path=['accounts'])
ERROR:
File "C:\Users\<me>\AppData\Local\Programs\Python\Python39\lib\site-packages\pandas\io\json\_normalize.py", line 423, in _json_normalize
raise NotImplementedError
作为参考,print(response['accounts']) 正确访问了响应的相关部分。这是错误中的 _normalize 部分,但我不明白如何应用它来解决问题:
if isinstance(data, list) and not data:
return DataFrame()
elif isinstance(data, dict):
# A bit of a hackjob
data = [data]
elif isinstance(data, abc.Iterable) and not isinstance(data, str):
# GH35923 Fix pd.json_normalize to not skip the first element of a
# generator input
data = list(data)
else:
raise NotImplementedError
如果我打印响应,它看起来像这样:
{'accounts': [{'account_id': 'account_1',
'balances': {'available': 300.0,
'current': 300.0,
'iso_currency_code': 'USD',
'limit': None,
'unofficial_currency_code': None},
'mask': 'xxx1',
'name': 'SAVINGS',
'official_name': 'Bank Savings',
'subtype': 'savings',
'type': 'depository'},
{'account_id': 'account_2',
'balances': {'available': 500.00,
'current': 600.0,
'iso_currency_code': 'USD',
'limit': None,
'unofficial_currency_code': None},
'mask': 'xxx2',
'name': 'CHECKING',
'official_name': 'Bank Checking',
'subtype': 'checking',
'type': 'depository'},
{'account_id': 'account_3',
'balances': {'available': 2000.00,
'current': 2000.00,
'iso_currency_code': 'USD',
'limit': None,
'unofficial_currency_code': None},
'mask': 'xxx3',
'name': 'BUSINESS CHECKING',
'official_name': 'Bank Business Checking',
'subtype': 'checking',
'type': 'depository'}],
'item': {'available_products': ['balance'],
'billed_products': ['auth', 'transactions'],
'consent_expiration_time': None,
'error': None,
'institution_id': 'ins_123xyz',
'item_id': 'item_123xyz',
'update_type': 'background',
'webhook': ''},
'request_id': 'request_123xyz'}
我假设如果 Plaid 的响应是标准的 JSON,单引号只在那里,因为 Python 的打印将它们从双引号转换而来。如果我将这个字符串作为基础并将单引号替换为双引号,并将 None 替换为 "None" ,我可以加载到数据框:
data = json.loads(responseString.replace("'", '"').replace('None', '"None"'))
df = pd.json_normalize(data, record_path=['accounts'])
print(df)
将此直接应用于 Plaid 的响应也有效:
data = str(response)
data = data.replace("'", '"').replace('None', '"None"')
data = json.loads(data)
df = pd.json_normalize(data, record_path=['accounts'])
我所拥有的似乎是一个临时的解决方法,但不是一个可靠的或预期的解决方案。有没有更好的到达方式?
更新 1:此 post 中第一个代码块的预期输出将产生以下数据帧,而不是错误:
account_id mask name official_name subtype ... balances.available balances.current balances.iso_currency_code balances.limit balances.unofficial_currency_code
0 account_1 xxx1 SAVINGS Bank Savings savings ... 300.0 300.0 USD None None
1 account_2 xxx2 CHECKING Bank Checking checking ... 500.0 600.0 USD None None
2 account_3 xxx3 BUSINESS CHECKING Bank Business Checking checking ... 2000.0 2000.0 USD None None
我可以通过解决方法获得相同的输出,但不明白为什么它是必要的,而且依靠用双引号替换单引号似乎不是获得结果的好方法。
更新 2:我在 2021 年 10 月 15 日使用非 docker 说明和 npm 安装了格子组件。
print(plaid.__version__)
8.2.0
$ py --version
Python 3.9.6
更新 3:根据 Stephen 建议的答案添加完整的解决方案。响应需要首先显式转换为字典,然后从那里进行处理。什么有效:
json_string = json.loads(json.dumps(response.to_dict()))
df = pd.json_normalize(json_string, record_path=['accounts'])
这让我可以省去转换为字符串后所需的所有变通方法,基本上直接加载到数据帧。
所以我认为解决方案是这样的
json_string = json.dumps(response.to_dict())
# which you can then input into a df
基本上,我们从 API 返回字典转移到返回 Python 模型。所以我们需要从 model
-> dictionary
-> json
旅行。 to_dict
是每个输出字典的模型上的方法,然后 json.dumps
接收字典并将其转换为有效的 JSON.
LMK 如果这对你有用:)