pandas 来自 Eurostat 的数据挖掘
pandas data mining from Eurostat
我正在开始一项工作,使用 python 和 pandas 来分析来自 Eurostat 等统计机构的数据。我发现有两种方法可以从 Eurostat 获取数据。
- pandas_datareader: 貌似很好用但是我发现获取一些具体数据有些问题
- pandasdmx:我发现它有点复杂,但它似乎是一个有前途的解决方案,但文档很差
我使用免费的 Azure 笔记本,online service,但我认为这不会使我的情况更加复杂。
让我解释一下 pandas_datareader 的问题。根据 pandas 文档,in the section API, there is this short documented package and it works. Apart from the shown example, that nicely works, a problem arises about other tables. For example, I can get data about European house price,ID table 是 prc_hpi_a,使用以下简单代码:
import pandas_datareader.data as web
import datetime
df = web.DataReader('prc_hpi_a', 'eurostat')
但是 table 具有三种类型的住宅数据:TOTAL、EXISTING 和 NEW。我只拿到了现房,其他的不知道怎么弄。您有针对这些类型过滤的解决方案吗?
其次是使用pandasdmx的路径。这里比较复杂。我的想法是把所有的数据都上传到一个pandasDataFrame,然后我想怎么分析就怎么分析。说起来容易,但是我没找到很多解释这段话的教程:upload data to pandas structures。例如,我找到 this tutorial,但我坚持第一步,即实例化一个客户端:
import pandasdmx
from pandasdmx import client
#estat=client('Eurostat', 'milk.db')
它 returns:
--------------------------------------------------------------------------- ImportError Traceback (most recent call
last) in ()
1 import pandasdmx
----> 2 from pandasdmx import client
3 estat=client('Eurostat', 'milk.db')
ImportError: 无法导入名称 'client'
这里有什么问题?我环顾四周,但没有解决这个问题
我也关注了this tutorial:
from pandasdmx import Request
estat = Request('ESTAT')
metadata = estat.datastructure('DSD_une_rt_a').write()
metadata.codelist.iloc[8:18]
resp = estat.data('une_rt_a', key={'GEO': 'EL+ES+IE'}, params={'startPeriod': '2007'})
data = resp.write(s for s in resp.data.series if s.key.AGE == 'TOTAL')
data.columns.names
data.columns.levels
data.loc[:, ('PC_ACT', 'TOTAL', 'T')]
我得到了数据,但我的目的是将它们上传到一个pandas结构(Series,DataFrame等。。),所以我可以根据我的工作轻松处理。怎么做?
实际上,我使用了这条工作线(在之前的工作线之下):
s=pd.DataFrame(data)
但是如果我尝试获取其他数据tables,它就不起作用了。让我用另一个关于 Harmonized Index Current Price table:
的例子来解释
estat = Request('ESTAT')
metadata = estat.datastructure('DSD_prc_hicp_midx').write()
resp = estat.data('prc_hicp_midx')
data = resp.write(s for s in resp.data.series if s.key.COICOP == 'CP00')
这里returns一个错误,就是:
--------------------------------------------------------------------------- AttributeError Traceback (most recent call
last) in ()
2 metadata = estat.datastructure('DSD_prc_hicp_midx').write()
3 resp = estat.data('prc_hicp_midx')
----> 4 data = resp.write(s for s in resp.data.series if s.key.COICOP == 'CP00')
5 #metadata.codelist
6 #data.loc[:, ('TOTAL', 'INX_Q','EA', 'Q')]
~/anaconda3_501/lib/python3.6/site-packages/pandasdmx/api.py in
getattr(self, name)
622 Make Message attributes directly readable from Response instance
623 '''
--> 624 return getattr(self.msg, name)
625
626 def _init_writer(self, writer):
AttributeError: 'DataMessage' object has no attribute 'data'
为什么现在收不到数据?现在怎么了?
我几乎花了一天时间四处寻找一些清晰的例子和解释。你有什么建议吗?是否有完整清晰的文档?我还发现 this page 和其他例子,解释了分类方案的使用,但它不适用于欧盟统计局(如在某些时候解释的那样)
这两种方法都可以工作,除了一些解释的问题,但我还需要一个建议来确定使用方法,查询欧盟统计局以及许多其他机构,如经合组织、世界银行等...
您能否指导我找到一个明确且可行的解决方案,即使每个机构的解决方案都不一样?
一般的解决方案是不要依赖像 datareader
这样过于具体的 API,而是去寻找源代码。您可以使用 datareader
的源代码作为灵感和操作指南。但最终当您需要从源获取数据时,您可能希望直接访问该源并加载数据。
一个非常流行的 HTTP API 工具是 requests
。您可以轻松地使用它从任何网站或 HTTP(S) 服务加载 JSON 数据。获得 JSON 后,您可以将其加载到 Pandas。由于此解决方案基于通用构建块,因此它几乎适用于 Web 上的任何数据源(与仅适用于 SDMX 数据源的 pandaSDMX 相反)。
这是我对我的问题的明确回答,适用于从 Eurostat 收集的每种类型的数据。我 post 在这里是因为它对很多人都有用。
让我举几个例子。他们制作了三个 pandas 系列(EU_unempl、EU_GDP、EU_intRates),其中包含数据和正确的时间索引
#----Unemployment Rate---------
dataEU_unempl=pd.read_json('http://ec.europa.eu/eurostat/wdds/rest/data/v2.1/json/en/ei_lmhr_m?geo=EA&indic=LM-UN-T-TOT&s_adj=NSA&unit=PC_ACT',typ='series',orient='table',numpy=True) #,typ='DataFrame',orient='table'
x=[]
for i in range(int(sorted(dataEU_unempl['value'].keys())[0]),1+int(sorted(dataEU_unempl['value'].keys(),reverse=True)[0])):
x=numpy.append(x,dataEU_unempl['value'][str(i)])
EU_unempl=pd.Series(x,index=pd.date_range((pd.to_datetime((sorted(dataEU_unempl['dimension']['time']['category']['index'].keys())[(sorted(int(v) for v in dataEU_unempl['value'].keys())[0])]),format='%YM%M')), periods=len(x), freq='M')) #'1/1993'
#----GDP---------
dataEU_GDP=pd.read_json('http://ec.europa.eu/eurostat/wdds/rest/data/v2.1/json/en/namq_10_gdp?geo=EA&na_item=B1GQ&s_adj=NSA&unit=CP_MEUR',typ='series',orient='table',numpy=True) #,typ='DataFrame',orient='table'
x=[]
for i in range((sorted(int(v) for v in dataEU_GDP['value'].keys())[0]),1+(sorted((int(v) for v in dataEU_GDP['value'].keys()),reverse=True))[0]):
x=numpy.append(x,dataEU_GDP['value'][str(i)])
EU_GDP=pd.Series(x,index=pd.date_range((pd.Timestamp(sorted(dataEU_GDP['dimension']['time']['category']['index'].keys())[(sorted(int(v) for v in dataEU_GDP['value'].keys())[0])])), periods=len(x), freq='Q'))
#----Money market interest rates---------
dataEU_intRates=pd.read_json('http://ec.europa.eu/eurostat/wdds/rest/data/v2.1/json/en/irt_st_m?geo=EA&intrt=MAT_ON',typ='series',orient='table',numpy=True) #,typ='DataFrame',orient='table'
x=[]
for i in range((sorted(int(v) for v in dataEU_intRates['value'].keys())[0]),1+(sorted((int(v) for v in dataEU_intRates['value'].keys()),reverse=True))[0]):
x=numpy.append(x,dataEU_intRates['value'][str(i)])
EU_intRates=pd.Series(x,index=pd.date_range((pd.to_datetime((sorted(dataEU_intRates['dimension']['time']['category']['index'].keys())[(sorted(int(v) for v in dataEU_intRates['value'].keys())[0])]),format='%YM%M')), periods=len(x), freq='M'))
加载 read_csv 和多个分隔符
来自批量下载存储库的 eurostat 数据的问题在于它们是制表符分隔的文件,其中前 3 列以逗号分隔。 Pandas read_csv() 如果指定 engine="python"
,则可以将多个分隔符作为正则表达式处理。这适用于某些数据集,但 OP 的数据集还包含标志,在最后一列中不能忽略。
# Load the house price index from the Eurostat bulk download facility
import pandas
code = "prc_hpi_a"
url = f"https://ec.europa.eu/eurostat/estat-navtree-portlet-prod/BulkDownloadListing?sort=1&file=data%2F{code}.tsv.gz" # Pandas.read_csv could almost read it directly with a multiple separator
df = pandas.read_csv(url, sep=",|\t| [^ ]?\t", na_values=":", engine="python")
# But the last column is a character column instead of a numeric because of the
# presence of a flag ": c" illustrated in the last line of the table extract
# below
# purchase,unit,geo\time\t 2006\t 2005
# DW_EXST,I10_A_AVG,AT\t :\t :
# DW_EXST,I10_A_AVG,BE\t 83.86\t 75.16
# DW_EXST,I10_A_AVG,BG\t 87.81\t 76.56
# DW_EXST,I10_A_AVG,CY\t :\t :
# DW_EXST,I10_A_AVG,CZ\t :\t :
# DW_EXST,I10_A_AVG,DE\t100.80\t101.10
# DW_EXST,I10_A_AVG,DK\t113.85\t 91.79
# DW_EXST,I10_A_AVG,EE\t156.23\t 98.69
# DW_EXST,I10_A_AVG,ES\t109.68\t :
# DW_EXST,I10_A_AVG,FI\t : c\t : c
加载 eurostat 软件包
还有一个名为 eurostat 的 python 包,它可以从批量工具中搜索数据集并将其加载到 pandas 数据框中。
加载2个不同的月度汇率数据集:
import eurostat
df1 = eurostat.get_data_df(code)
bulk download facility的内容table可以用
阅读
toc_url = "https://ec.europa.eu/eurostat/estat-navtree-portlet-prod/BulkDownloadListing?sort=1&file=table_of_contents_en.txt"
toc2 = pandas.read_csv(toc_url, sep="\t")
# Remove white spaces at the beginning and end of strings
toc2 = toc2.applymap(lambda x: x.strip() if isinstance(x, str) else x)
或与
toc = eurostat.get_toc_df()
toc0 = (eurostat.subset_toc_df(toc, "exchange"))
最后一行搜索标题中包含“exchange”的数据集
重塑为长格式
将 eurostat 数据重塑为长格式可能会有用
与
if any(df.columns.str.contains("time")):
time_column = df.columns[df.columns.str.contains("time")][-1]
# Id columns are before the time columns
id_columns = df.loc[:, :time_column].columns
df = df.melt(id_vars=id_columns, var_name="period", value_name="value")
# Remove "\time" from the rightmost column of the index
df = df.rename(columns=lambda x: re.sub(r"\time", "", x))
我正在开始一项工作,使用 python 和 pandas 来分析来自 Eurostat 等统计机构的数据。我发现有两种方法可以从 Eurostat 获取数据。
- pandas_datareader: 貌似很好用但是我发现获取一些具体数据有些问题
- pandasdmx:我发现它有点复杂,但它似乎是一个有前途的解决方案,但文档很差
我使用免费的 Azure 笔记本,online service,但我认为这不会使我的情况更加复杂。
让我解释一下 pandas_datareader 的问题。根据 pandas 文档,in the section API, there is this short documented package and it works. Apart from the shown example, that nicely works, a problem arises about other tables. For example, I can get data about European house price,ID table 是 prc_hpi_a,使用以下简单代码:
import pandas_datareader.data as web
import datetime
df = web.DataReader('prc_hpi_a', 'eurostat')
但是 table 具有三种类型的住宅数据:TOTAL、EXISTING 和 NEW。我只拿到了现房,其他的不知道怎么弄。您有针对这些类型过滤的解决方案吗?
其次是使用pandasdmx的路径。这里比较复杂。我的想法是把所有的数据都上传到一个pandasDataFrame,然后我想怎么分析就怎么分析。说起来容易,但是我没找到很多解释这段话的教程:upload data to pandas structures。例如,我找到 this tutorial,但我坚持第一步,即实例化一个客户端:
import pandasdmx
from pandasdmx import client
#estat=client('Eurostat', 'milk.db')
它 returns:
--------------------------------------------------------------------------- ImportError Traceback (most recent call last) in () 1 import pandasdmx ----> 2 from pandasdmx import client 3 estat=client('Eurostat', 'milk.db')
ImportError: 无法导入名称 'client'
这里有什么问题?我环顾四周,但没有解决这个问题
我也关注了this tutorial:
from pandasdmx import Request
estat = Request('ESTAT')
metadata = estat.datastructure('DSD_une_rt_a').write()
metadata.codelist.iloc[8:18]
resp = estat.data('une_rt_a', key={'GEO': 'EL+ES+IE'}, params={'startPeriod': '2007'})
data = resp.write(s for s in resp.data.series if s.key.AGE == 'TOTAL')
data.columns.names
data.columns.levels
data.loc[:, ('PC_ACT', 'TOTAL', 'T')]
我得到了数据,但我的目的是将它们上传到一个pandas结构(Series,DataFrame等。。),所以我可以根据我的工作轻松处理。怎么做? 实际上,我使用了这条工作线(在之前的工作线之下):
s=pd.DataFrame(data)
但是如果我尝试获取其他数据tables,它就不起作用了。让我用另一个关于 Harmonized Index Current Price table:
的例子来解释estat = Request('ESTAT')
metadata = estat.datastructure('DSD_prc_hicp_midx').write()
resp = estat.data('prc_hicp_midx')
data = resp.write(s for s in resp.data.series if s.key.COICOP == 'CP00')
这里returns一个错误,就是:
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) in () 2 metadata = estat.datastructure('DSD_prc_hicp_midx').write() 3 resp = estat.data('prc_hicp_midx') ----> 4 data = resp.write(s for s in resp.data.series if s.key.COICOP == 'CP00') 5 #metadata.codelist 6 #data.loc[:, ('TOTAL', 'INX_Q','EA', 'Q')]
~/anaconda3_501/lib/python3.6/site-packages/pandasdmx/api.py in getattr(self, name) 622 Make Message attributes directly readable from Response instance 623 ''' --> 624 return getattr(self.msg, name) 625 626 def _init_writer(self, writer):
AttributeError: 'DataMessage' object has no attribute 'data'
为什么现在收不到数据?现在怎么了?
我几乎花了一天时间四处寻找一些清晰的例子和解释。你有什么建议吗?是否有完整清晰的文档?我还发现 this page 和其他例子,解释了分类方案的使用,但它不适用于欧盟统计局(如在某些时候解释的那样)
这两种方法都可以工作,除了一些解释的问题,但我还需要一个建议来确定使用方法,查询欧盟统计局以及许多其他机构,如经合组织、世界银行等... 您能否指导我找到一个明确且可行的解决方案,即使每个机构的解决方案都不一样?
一般的解决方案是不要依赖像 datareader
这样过于具体的 API,而是去寻找源代码。您可以使用 datareader
的源代码作为灵感和操作指南。但最终当您需要从源获取数据时,您可能希望直接访问该源并加载数据。
一个非常流行的 HTTP API 工具是 requests
。您可以轻松地使用它从任何网站或 HTTP(S) 服务加载 JSON 数据。获得 JSON 后,您可以将其加载到 Pandas。由于此解决方案基于通用构建块,因此它几乎适用于 Web 上的任何数据源(与仅适用于 SDMX 数据源的 pandaSDMX 相反)。
这是我对我的问题的明确回答,适用于从 Eurostat 收集的每种类型的数据。我 post 在这里是因为它对很多人都有用。
让我举几个例子。他们制作了三个 pandas 系列(EU_unempl、EU_GDP、EU_intRates),其中包含数据和正确的时间索引
#----Unemployment Rate---------
dataEU_unempl=pd.read_json('http://ec.europa.eu/eurostat/wdds/rest/data/v2.1/json/en/ei_lmhr_m?geo=EA&indic=LM-UN-T-TOT&s_adj=NSA&unit=PC_ACT',typ='series',orient='table',numpy=True) #,typ='DataFrame',orient='table'
x=[]
for i in range(int(sorted(dataEU_unempl['value'].keys())[0]),1+int(sorted(dataEU_unempl['value'].keys(),reverse=True)[0])):
x=numpy.append(x,dataEU_unempl['value'][str(i)])
EU_unempl=pd.Series(x,index=pd.date_range((pd.to_datetime((sorted(dataEU_unempl['dimension']['time']['category']['index'].keys())[(sorted(int(v) for v in dataEU_unempl['value'].keys())[0])]),format='%YM%M')), periods=len(x), freq='M')) #'1/1993'
#----GDP---------
dataEU_GDP=pd.read_json('http://ec.europa.eu/eurostat/wdds/rest/data/v2.1/json/en/namq_10_gdp?geo=EA&na_item=B1GQ&s_adj=NSA&unit=CP_MEUR',typ='series',orient='table',numpy=True) #,typ='DataFrame',orient='table'
x=[]
for i in range((sorted(int(v) for v in dataEU_GDP['value'].keys())[0]),1+(sorted((int(v) for v in dataEU_GDP['value'].keys()),reverse=True))[0]):
x=numpy.append(x,dataEU_GDP['value'][str(i)])
EU_GDP=pd.Series(x,index=pd.date_range((pd.Timestamp(sorted(dataEU_GDP['dimension']['time']['category']['index'].keys())[(sorted(int(v) for v in dataEU_GDP['value'].keys())[0])])), periods=len(x), freq='Q'))
#----Money market interest rates---------
dataEU_intRates=pd.read_json('http://ec.europa.eu/eurostat/wdds/rest/data/v2.1/json/en/irt_st_m?geo=EA&intrt=MAT_ON',typ='series',orient='table',numpy=True) #,typ='DataFrame',orient='table'
x=[]
for i in range((sorted(int(v) for v in dataEU_intRates['value'].keys())[0]),1+(sorted((int(v) for v in dataEU_intRates['value'].keys()),reverse=True))[0]):
x=numpy.append(x,dataEU_intRates['value'][str(i)])
EU_intRates=pd.Series(x,index=pd.date_range((pd.to_datetime((sorted(dataEU_intRates['dimension']['time']['category']['index'].keys())[(sorted(int(v) for v in dataEU_intRates['value'].keys())[0])]),format='%YM%M')), periods=len(x), freq='M'))
加载 read_csv 和多个分隔符
来自批量下载存储库的 eurostat 数据的问题在于它们是制表符分隔的文件,其中前 3 列以逗号分隔。 Pandas read_csv() 如果指定 engine="python"
,则可以将多个分隔符作为正则表达式处理。这适用于某些数据集,但 OP 的数据集还包含标志,在最后一列中不能忽略。
# Load the house price index from the Eurostat bulk download facility
import pandas
code = "prc_hpi_a"
url = f"https://ec.europa.eu/eurostat/estat-navtree-portlet-prod/BulkDownloadListing?sort=1&file=data%2F{code}.tsv.gz" # Pandas.read_csv could almost read it directly with a multiple separator
df = pandas.read_csv(url, sep=",|\t| [^ ]?\t", na_values=":", engine="python")
# But the last column is a character column instead of a numeric because of the
# presence of a flag ": c" illustrated in the last line of the table extract
# below
# purchase,unit,geo\time\t 2006\t 2005
# DW_EXST,I10_A_AVG,AT\t :\t :
# DW_EXST,I10_A_AVG,BE\t 83.86\t 75.16
# DW_EXST,I10_A_AVG,BG\t 87.81\t 76.56
# DW_EXST,I10_A_AVG,CY\t :\t :
# DW_EXST,I10_A_AVG,CZ\t :\t :
# DW_EXST,I10_A_AVG,DE\t100.80\t101.10
# DW_EXST,I10_A_AVG,DK\t113.85\t 91.79
# DW_EXST,I10_A_AVG,EE\t156.23\t 98.69
# DW_EXST,I10_A_AVG,ES\t109.68\t :
# DW_EXST,I10_A_AVG,FI\t : c\t : c
加载 eurostat 软件包
还有一个名为 eurostat 的 python 包,它可以从批量工具中搜索数据集并将其加载到 pandas 数据框中。 加载2个不同的月度汇率数据集:
import eurostat
df1 = eurostat.get_data_df(code)
bulk download facility的内容table可以用
阅读toc_url = "https://ec.europa.eu/eurostat/estat-navtree-portlet-prod/BulkDownloadListing?sort=1&file=table_of_contents_en.txt"
toc2 = pandas.read_csv(toc_url, sep="\t")
# Remove white spaces at the beginning and end of strings
toc2 = toc2.applymap(lambda x: x.strip() if isinstance(x, str) else x)
或与
toc = eurostat.get_toc_df()
toc0 = (eurostat.subset_toc_df(toc, "exchange"))
最后一行搜索标题中包含“exchange”的数据集
重塑为长格式
将 eurostat 数据重塑为长格式可能会有用 与
if any(df.columns.str.contains("time")):
time_column = df.columns[df.columns.str.contains("time")][-1]
# Id columns are before the time columns
id_columns = df.loc[:, :time_column].columns
df = df.melt(id_vars=id_columns, var_name="period", value_name="value")
# Remove "\time" from the rightmost column of the index
df = df.rename(columns=lambda x: re.sub(r"\time", "", x))