Determining Data Availability
The only way to be certain whether data is available for a given set of dimension filters is to make a request to the API and see what comes back. imf_get returns an empty data frame and warns when a query matches nothing; if that happens, relax one dimension at a time to find the one that is over-restrictive.
Working with Large Data Frames
Inspecting Data
imfp outputs data in pandas DataFrames, so you will want to use the pandas package for its functions for viewing and manipulating this object type.
For large datasets, you can use the pandas library’s info() method to get a quick summary of the data frame, including the number of rows and columns, the count of non-missing values, the column names, and the data types.
import imfp
import pandas as pd
# Set float format to 2 decimal places for pandas display output
pd.set_option('display.float_format', lambda x: '%.2f' % x)
df: pd.DataFrame = imfp.imf_get(
"PCPS",
indicator=["PCOAL"],
data_transformation=["INDEX"],
)
# Quick summary of DataFrame
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 587 entries, 0 to 586
Data columns (total 6 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 COUNTRY 587 non-null object
1 INDICATOR 587 non-null object
2 DATA_TRANSFORMATION 587 non-null object
3 FREQUENCY 587 non-null object
4 TIME_PERIOD 587 non-null object
5 OBS_VALUE 587 non-null float64
dtypes: float64(1), object(5)
memory usage: 27.6+ KB
Alternatively, you can use the head() method to view the first 5 rows of the data frame.
# View first 5 rows of DataFrame
df.head()
|
COUNTRY |
INDICATOR |
DATA_TRANSFORMATION |
FREQUENCY |
TIME_PERIOD |
OBS_VALUE |
| 0 |
G001 |
PCOAL |
INDEX |
A |
1992 |
49.89 |
| 1 |
G001 |
PCOAL |
INDEX |
A |
1993 |
43.28 |
| 2 |
G001 |
PCOAL |
INDEX |
A |
1994 |
45.21 |
| 3 |
G001 |
PCOAL |
INDEX |
A |
1995 |
55.43 |
| 4 |
G001 |
PCOAL |
INDEX |
A |
1996 |
53.18 |
Cleaning Data
Categorical Conversion
imf_get already returns OBS_VALUE as a float, so no numeric conversion is needed. Dimension columns come back as strings, and converting them to pandas categoricals can save a great deal of memory on large frames:
# Convert dimension columns to category type
categorical_cols = [
"FREQUENCY",
"COUNTRY",
"INDICATOR"
]
df[categorical_cols] = df[categorical_cols].astype("category")
NA Removal
Observations the IMF reports as missing come back as NaN, so you may want to drop them:
# Drop rows with missing values
df = df.dropna()
Time Period Conversion
The TIME_PERIOD column is the awkward one, because its format depends on the frequency of the series.
Annual data is formatted as a four-digit year, such as “2000”, which converts trivially to numeric. Quarterly data, though, is formatted as “2000-Q1”, monthly data as “2000-M01”, and so on.
You can use the pandas library’s to_datetime() method with the format="mixed" argument to convert this column to a datetime object in a format-agnostic way:
# Convert TIME_PERIOD to datetime
df["datetime"] = pd.to_datetime(df["TIME_PERIOD"], format="mixed")
df[["FREQUENCY", "datetime"]].head()
|
FREQUENCY |
datetime |
| 0 |
A |
1992-01-01 |
| 1 |
A |
1993-01-01 |
| 2 |
A |
1994-01-01 |
| 3 |
A |
1995-01-01 |
| 4 |
A |
1996-01-01 |
Alternatively, you can split the TIME_PERIOD column into separate columns for year, quarter, and month, and then convert each to a numeric value:
# Split TIME_PERIOD into separate columns
df["year"] = df["TIME_PERIOD"].str.extract(r"(\d{4})")[0]
df["quarter"] = df["TIME_PERIOD"].str.extract(r"[Q](\d{1})")[0]
df["month"] = df["TIME_PERIOD"].str.extract(r"[M](\d{2})")[0]
# Convert year, quarter, and month to numeric
df["year"] = pd.to_numeric(df["year"])
df["quarter"] = pd.to_numeric(df["quarter"])
df["month"] = pd.to_numeric(df["month"])
# Return head for non-na months
df[["TIME_PERIOD", "year", "quarter", "month"]].dropna(subset=["month"]).head()
|
TIME_PERIOD |
year |
quarter |
month |
| 34 |
1992-M01 |
1992 |
NaN |
1.00 |
| 35 |
1992-M02 |
1992 |
NaN |
2.00 |
| 36 |
1992-M03 |
1992 |
NaN |
3.00 |
| 37 |
1992-M04 |
1992 |
NaN |
4.00 |
| 38 |
1992-M05 |
1992 |
NaN |
5.00 |
Summarizing Data
After converting columns to numeric, you can use the describe() function to get a quick summary of the statistical properties of these, including the count of rows, the mean, the standard deviation, the minimum and maximum values, and the quartiles.
# Statistical summary
df.describe()
|
OBS_VALUE |
datetime |
year |
quarter |
month |
| count |
587.00 |
587 |
587.00 |
138.00 |
415.00 |
| mean |
113.28 |
2008-11-08 17:05:29.608177152 |
2008.77 |
2.49 |
6.46 |
| min |
33.62 |
1992-01-01 00:00:00 |
1992.00 |
1.00 |
1.00 |
| 25% |
50.61 |
2000-01-01 00:00:09.500000 |
2000.00 |
1.25 |
3.00 |
| 50% |
94.61 |
2009-01-01 00:00:03 |
2009.00 |
2.00 |
6.00 |
| 75% |
145.70 |
2017-05-16 12:00:00 |
2017.00 |
3.00 |
9.00 |
| max |
577.58 |
2026-04-01 00:00:00 |
2026.00 |
4.00 |
12.00 |
| std |
86.94 |
NaN |
9.98 |
1.12 |
3.45 |
Viewing Data
For large data frames, it can be useful to view the data in a browser window. To facilitate this, you can define a View() function as follows. This function will save the data frame to a temporary HTML file and open it in your default web browser.
import tempfile
import webbrowser
# Define a simple function to view data frame in a browser window
def View(df: pd.DataFrame):
html = df.to_html()
with tempfile.NamedTemporaryFile('w',
delete=False, suffix='.html') as f:
url = 'file://' + f.name
f.write(html)
webbrowser.open(url)
# Call the function
View(df)