#python #json #pandas #request #sdmx
#python #json #pandas #запрос #sdmx
Вопрос:
Я борюсь с данными Международного валютного фонда, которые представлены в формате JSON. После проверки некоторых сообщений я не мог понять, как это сделать.
Что я пробовал
import requests
import pandas as pd
import json
# These are the variables I want to have as columns, plus setting a time index
var = ['NGDP_XDC', 'NCP_XDC', 'NCGG_XDC', 'NFI_XDC', 'NINV_XDC', 'NX_XDC',
'NM_XDC', 'NSDGDP_XDC', 'NGDP_R_K_IX', 'NGDP_D_IX']
# URL for the IMF JSON Restful Web Service,
# IFS database
base = 'http://dataservices.imf.org/REST/SDMX_JSON.svc/CompactData/IFS/'
period = 'A'
country = 'MX'
var = 'NGDP_XDC NCP_XDC NCGG_XDC NFI_XDC NINV_XDC NX_XDC NM_XDC NSDGDP_XDC NGDP_R_K_IX NGDP_D_IX'
time = '?startPeriod=1970amp;endPeriod=2019'
# Get data from the above URL using the requests package
url = base period '.' country '.' var '.' time
response = requests.get(url)
dictr = response.json()
… пока все хорошо… Тем не менее, это шаг, с которым я борюсь
flat = dictr['CompactData']['DataSet']['Series']
temp = pd.json_normalize(flat)
temp = temp.drop(columns=['@FREQ', '@REF_AREA', '@UNIT_MULT', '@BASE_YEAR'])
Я ожидал получить плоский файл, который я мог бы повернуть по своему желанию. Тем не менее, это то, что я получаю
@INDICATOR @TIME_FORMAT Obs
0 NINV_XDC P1Y [{'@TIME_PERIOD': '1970', '@OBS_VALUE': '37.21...
1 NX_XDC P1Y [{'@TIME_PERIOD': '1970', '@OBS_VALUE':
В который я понятия не имею, как его преобразовать
year variable1 ... variableN
1970 10 ... 45
1980 20 ... 12
.
.
.
2019 15 ... 10
Ответ №1:
Возможно, это подтолкнет вас в правильном направлении.
Значение ['CompactData']['DataSet']['Series']
— это a dict
, которое содержит список dicts в качестве значения, которое вам нужно.
Итак, вам нужно сгладить это:
series = response['CompactData']['DataSet']['Series']
flat = [item for sublist in [i['Obs'] for i in series] for item in sublist]
Собрать все это вместе:
import requests
import pandas as pd
# These are the variables I want to have as columns, plus setting a time index
var = [
'NGDP_XDC', 'NCP_XDC', 'NCGG_XDC', 'NFI_XDC', 'NINV_XDC', 'NX_XDC',
'NM_XDC', 'NSDGDP_XDC', 'NGDP_R_K_IX', 'NGDP_D_IX',
]
base = 'http://dataservices.imf.org/REST/SDMX_JSON.svc/CompactData/IFS/'
period = 'A'
country = 'MX'
time = '?startPeriod=1970amp;endPeriod=2019'
# Get data from the above URL using the requests package
url = f"{base}{period}.{country}.{' '.join(var)}.{time}"
response = requests.get(url).json()
series = response['CompactData']['DataSet']['Series']
flat = [item for sublist in [i['Obs'] for i in series] for item in sublist]
print(pd.DataFrame(flat))
Вывод:
@TIME_PERIOD @OBS_VALUE @OBS_STATUS
0 1970 37.210816346586 NaN
1 1971 35.6027864361386 NaN
2 1972 36.123021665698 NaN
3 1973 50.9603299629663 NaN
4 1974 80.992068185601 NaN
.. ... ... ...
[499 rows x 3 columns]
Ответ №2:
Я реализовал ваш nudge гораздо менее элегантным способом, поскольку не мог понять, как извлекать коды переменных и индекс времени из вашей процедуры. Это также работает:
url = f"{base}{period}.{country}.{' '.join(var)}.{time}"
response = requests.get(url).json()
series = response['CompactData']['DataSet']['Series']
nipa = pd.DataFrame(index=range(1970, 2020))
N = len(var)
for n in range(0, N):
temp = pd.DataFrame(series[n]['Obs'], index=range(1970, 2020))
temp = temp.drop(columns='@TIME_PERIOD')
temp.rename(columns={'@OBS_VALUE': var[n]}, inplace=True)
nipa = pd.merge(nipa, temp, left_index=True, right_index=True)