|
| 1 | +--- |
| 2 | +jupytext: |
| 3 | + text_representation: |
| 4 | + extension: .md |
| 5 | + format_name: myst |
| 6 | + format_version: 0.13 |
| 7 | + jupytext_version: 1.14.5 |
| 8 | +kernelspec: |
| 9 | + display_name: Python 3 (ipykernel) |
| 10 | + language: python |
| 11 | + name: python3 |
| 12 | +--- |
| 13 | + |
| 14 | ++++ {"user_expressions": []} |
| 15 | + |
| 16 | +# Price Level Histories |
| 17 | + |
| 18 | +## Ends of Four Big Inflations |
| 19 | + |
| 20 | + |
| 21 | + |
| 22 | +We want to construct four graphs from "The Ends of Four Big Inflations" from chapter 3 of {cite}` |
| 23 | + |
| 24 | +This is chapter 3 of the book **Rational Expectations and Inflation** that I shared with you a couple of days ago. |
| 25 | + |
| 26 | + |
| 27 | +```python |
| 28 | +import numpy as np |
| 29 | +import pandas as pd |
| 30 | +import matplotlib.pyplot as plt |
| 31 | +import matplotlib.dates as mdates |
| 32 | +import datetime |
| 33 | +``` |
| 34 | + |
| 35 | +```python |
| 36 | +!pip install xlrd |
| 37 | +``` |
| 38 | + |
| 39 | +The graphs depict logarithms of price levels during the early post World War I years for four countries: |
| 40 | + |
| 41 | + * Figure 3.1, Retail prices Austria 1921-1924 (page 42) |
| 42 | + * Figure 3.2, Wholesale prices Hungary, 1921-1924 (page 43) |
| 43 | + * Figure 3.3, Wholesale prices, Poland, 1921-1924 (page 44) |
| 44 | + * Figure pd.dataframe(3.4, Wholesale prices, Germany, 1919-1924 (page 45) |
| 45 | + |
| 46 | +Data underlying these graphs appear in the tables in the appendix; all of the data have been organized into a spreadsheet *chapter_3.xls* that I include in our dropbox folder. |
| 47 | + |
| 48 | +The spreadsheet refers to the tables that I now describe for each of our four countries. |
| 49 | + |
| 50 | + |
| 51 | +## Tweak request for Jiacheng |
| 52 | + |
| 53 | +* for each of the four countries, please delete the graphs of the "money supplies" and "real balances" in the right panels. So now we'll just have your excellent graphs of the price level and exchange rate |
| 54 | + |
| 55 | +* for each graph please add a caption below the graph just saying the country name. Maybe Zejin can quickly tell you how to do this. |
| 56 | + |
| 57 | +* for Poland I think that there are some additional price level data in the table, but their units have changed. Please take a look at figure 3.3. in the chapter. I am pretty sure that to draw that graph I just made a guess about the units change -- sort of using "continuity" -- and adjusted the units of the second series and spliced the series to get the one in figure 3.3. We can talk about this if you wish |
| 58 | + |
| 59 | +* for Germany, I'd like to do another "splicing operation" to avoid the big jump down in the price series and the exchange rate series. What those jumps reflect is the "units change" associated with the "currency reform". It was a pure units change. |
| 60 | + |
| 61 | + * Here is one idea -- make two versions of the graph in two separate graphs. The first version is what you have |
| 62 | + |
| 63 | + * The second version does the "splicing" by converting the new units to the old so that there is no drop. Then the graphs will be "continuous. |
| 64 | + |
| 65 | + * By comparing the graphs we can teach about the "currency reform" |
| 66 | + |
| 67 | + |
| 68 | + |
| 69 | +* Comment: I really like the way you put the exchange rate and the price level on the same graph for each country. Overall the graphs are great -- really exciting to me! And I love the "long series" graph at the end. |
| 70 | + |
| 71 | +* Thanks so much. |
| 72 | + |
| 73 | + |
| 74 | + |
| 75 | +```python |
| 76 | +def process_entry(entry): |
| 77 | + "Clean each entry of a dataframe." |
| 78 | + |
| 79 | + if type(entry) == str: |
| 80 | + # remove leading and trailing whitespace |
| 81 | + entry = entry.strip() |
| 82 | + # remove comma |
| 83 | + entry = entry.replace(',', '') |
| 84 | + |
| 85 | + # remove HTML markers |
| 86 | + item_to_remove = ['<s>a</s>', '<s>c</s>', '<s>d</s>', '<s>e</s>'] |
| 87 | + |
| 88 | + # <s>b</s> represents a billion |
| 89 | + if '<s>b</s>' in entry: |
| 90 | + entry = entry.replace('<s>b</s>', '') |
| 91 | + entry = float(entry) * 1e9 |
| 92 | + else: |
| 93 | + for item in item_to_remove: |
| 94 | + if item in entry: |
| 95 | + entry = entry.replace(item, '') |
| 96 | + return entry |
| 97 | + |
| 98 | +def process_df(df): |
| 99 | + "Clean and reorganize the entire dataframe." |
| 100 | + |
| 101 | + # remove HTML markers from column names |
| 102 | + for item in ['<s>a</s>', '<s>c</s>', '<s>d</s>', '<s>e</s>']: |
| 103 | + df.columns = df.columns.str.replace(item, '') |
| 104 | + |
| 105 | + df['Year'] = df['Year'].apply(lambda x: int(x)) |
| 106 | + |
| 107 | + # set index to date time |
| 108 | + df = df.set_index( |
| 109 | + pd.to_datetime((df['Year'].astype(str) + df['Month'].astype(str)), format='%Y%B')) |
| 110 | + df = df.drop(['Year', 'Month'], axis=1) |
| 111 | + |
| 112 | + # handle duplicates by keeping the first |
| 113 | + df = df[~df.index.duplicated(keep='first')] |
| 114 | + |
| 115 | + # convert to numeric |
| 116 | + df = df.applymap(lambda x: float(x) if x != '—' else np.nan) |
| 117 | + |
| 118 | + # finally, we only focus on data between 1919 and 1925 |
| 119 | + mask = (df.index >= '1919-01-01') & (df.index < '1925-01-01') |
| 120 | + df = df.loc[mask] |
| 121 | + |
| 122 | + return df |
| 123 | + |
| 124 | +def create_plot(p_seq, e_seq, index, labs, ax): |
| 125 | + |
| 126 | + p_lab, e_lab = labs |
| 127 | + |
| 128 | + # price and exchange rates |
| 129 | + ax.plot(index, p_seq, label=p_lab, color='tab:blue') |
| 130 | + ax1 = ax.twinx() |
| 131 | + ax1.plot([None], [None], label=p_lab, color='tab:blue') |
| 132 | + ax1.plot(index, e_seq, label=e_lab, color='tab:orange') |
| 133 | + ax.set_yscale('log') |
| 134 | + ax1.set_yscale('log') |
| 135 | + |
| 136 | + ax.xaxis.set_major_locator(mdates.MonthLocator(interval=5)) |
| 137 | + ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %Y')) |
| 138 | + for label in ax.get_xticklabels(): |
| 139 | + label.set_rotation(45) |
| 140 | + |
| 141 | + ax.text(-0.08, 1.03, 'Price Level', transform=ax.transAxes) |
| 142 | + ax.text(0.92, 1.03, 'Exchange Rate', transform=ax.transAxes) |
| 143 | + |
| 144 | + ax1.legend(loc='upper left') |
| 145 | + |
| 146 | + return ax1 |
| 147 | +``` |
| 148 | + |
| 149 | +```python |
| 150 | +# import data |
| 151 | +xls = pd.ExcelFile('datasets/chapter_3.xlsx') |
| 152 | + |
| 153 | +# unpack and combine all series |
| 154 | +sheet_index = [(2, 3, 4), (9, 10), (14, 15, 16), (21, 18, 19)] |
| 155 | +remove_row = [(-2, -2, -2), (-7, -10), (-6, -4, -3), (-19, -3, -6)] |
| 156 | + |
| 157 | +df_list = [] |
| 158 | + |
| 159 | +for i in range(4): |
| 160 | + |
| 161 | + indices, rows = sheet_index[i], remove_row[i] |
| 162 | + sheet_list = [pd.read_excel(xls, 'Table3.' + str(ind), header=1).iloc[:row].applymap(process_entry) |
| 163 | + for ind, row in zip(indices, rows)] |
| 164 | + |
| 165 | + sheet_list = [process_df(df) for df in sheet_list] |
| 166 | + df_list.append(pd.concat(sheet_list, axis=1)) |
| 167 | + |
| 168 | +df_Aus, df_Hung, df_Pol, df_Germ = df_list |
| 169 | +``` |
| 170 | + |
| 171 | +### Austria |
| 172 | + |
| 173 | +* Table 3.2, money supply, $\exp M$ |
| 174 | +* Table 3.3, rdf_Aus.indexetail prices, $\exp p$ |
| 175 | +* Table 3.4, exchange rate with US |
| 176 | + |
| 177 | +```python |
| 178 | +df_Aus.head(5) |
| 179 | +``` |
| 180 | + |
| 181 | +```python |
| 182 | +p_seq = df_Aus['Retail price index, 52 commodities'] |
| 183 | +e_seq = df_Aus['Exchange Rate'] |
| 184 | + |
| 185 | +lab = ['Retail Price Index', 'Exchange Rate'] |
| 186 | + |
| 187 | +# create plot |
| 188 | +fig, ax = plt.subplots(figsize=[10,7], dpi=200) |
| 189 | +_ = create_plot(p_seq, e_seq, df_Aus.index, lab, ax) |
| 190 | + |
| 191 | +# connect disjunct parts |
| 192 | +plt.figtext(0.5, 0.0, 'Austria', horizontalalignment='center', fontsize=12) |
| 193 | +plt.show() |
| 194 | +``` |
| 195 | + |
| 196 | +### Hungary |
| 197 | + |
| 198 | +* Table 3.9, money supply, $\exp M$ |
| 199 | +* Table 3.10, price level $\exp p$ and exchange rate |
| 200 | + |
| 201 | + |
| 202 | +```python |
| 203 | +df_Hung.head(5) |
| 204 | +``` |
| 205 | + |
| 206 | +```python |
| 207 | +m_seq = df_Hung['Notes in circulation'] |
| 208 | +p_seq = df_Hung['Hungarian index of prices'] |
| 209 | +e_seq = 1/df_Hung['Cents per crown in New York'] |
| 210 | +rb_seq = np.log(m_seq) - np.log(p_seq) |
| 211 | + |
| 212 | +lab = ['Hungarian Index of Prices', '1/Cents per Crown in New York'] |
| 213 | + |
| 214 | +# create plot |
| 215 | +fig, ax = plt.subplots(figsize=[10,7], dpi=200) |
| 216 | +_ = create_plot(p_seq, e_seq, df_Hung.index, lab, ax) |
| 217 | + |
| 218 | +plt.figtext(0.5, 0.0, 'Hungary', horizontalalignment='center', fontsize=12) |
| 219 | +plt.show() |
| 220 | +``` |
| 221 | + |
| 222 | +### Poland |
| 223 | + |
| 224 | +* Table 3.14, money supply, $\exp M$ |
| 225 | +* Table 3.15, price level $\exp p$ |
| 226 | +* Table 3.15, exchange rate |
| 227 | + |
| 228 | + |
| 229 | +Jiacheng: |
| 230 | + |
| 231 | +I spliced the three series - Wholesale price index, Wholesale Price Index: On paper currency basis, and Wholesale Price Index: On zloty basis. I made the adjustment by adjusting the sequence based on the price level ratio at the last period of the available previous series and glue them to a single series. |
| 232 | + |
| 233 | +I dropped the exchange rate after June 1924, when zloty was adopted, because we don't have the price measured in zloty and old currency in June to compute the exchange rate adjustment. |
| 234 | + |
| 235 | +```python |
| 236 | +df_Pol.head(5) |
| 237 | +``` |
| 238 | + |
| 239 | +```python |
| 240 | +# splice three price series in different units |
| 241 | +p_seq1 = df_Pol['Wholesale price index'].copy() |
| 242 | +p_seq2 = df_Pol['Wholesale Price Index: On paper currency basis'].copy() |
| 243 | +p_seq3 = df_Pol['Wholesale Price Index: On zloty basis'].copy() |
| 244 | + |
| 245 | +# non-nan part |
| 246 | +ch_index_1 = p_seq1[~p_seq1.isna()].index[-1] |
| 247 | +ch_index_2 = p_seq2[~p_seq2.isna()].index[-2] |
| 248 | + |
| 249 | +adj_ratio12 = p_seq1[ch_index_1]/p_seq2[ch_index_1] |
| 250 | +adj_ratio23 = p_seq2[ch_index_2]/p_seq3[ch_index_2] |
| 251 | + |
| 252 | +# glue three series |
| 253 | +p_seq = pd.concat([p_seq1[:ch_index_1], |
| 254 | + adj_ratio12 * p_seq2[ch_index_1:ch_index_2], |
| 255 | + adj_ratio23 * p_seq3[ch_index_2:]]) |
| 256 | +p_seq = p_seq[~p_seq.index.duplicated(keep='first')] |
| 257 | + |
| 258 | +# exchange rate |
| 259 | +e_seq = 1/df_Pol['Cents per Polish mark (zloty after May 1924)'] |
| 260 | +e_seq[e_seq.index > '05-01-1924'] = np.nan |
| 261 | +``` |
| 262 | + |
| 263 | +```python |
| 264 | +lab = ['Wholesale Price Index', '1/Cents per Polish Mark'] |
| 265 | + |
| 266 | +# create plot |
| 267 | +fig, ax = plt.subplots(figsize=[10,7], dpi=200) |
| 268 | +ax1 = create_plot(p_seq, e_seq, df_Pol.index, lab, ax) |
| 269 | + |
| 270 | +plt.figtext(0.5, 0.0, 'Poland', horizontalalignment='center', fontsize=12) |
| 271 | +plt.show() |
| 272 | +``` |
| 273 | + |
| 274 | +### Germany |
| 275 | + |
| 276 | +* Table 3.21, money supply, $\exp M$ (last column) |
| 277 | +* Table 3.18, wholesale price level $\exp p$ |
| 278 | +* Table 3.19, exchange rate |
| 279 | + |
| 280 | +```python |
| 281 | +df_Germ.head(5) |
| 282 | +``` |
| 283 | + |
| 284 | + |
| 285 | +```python |
| 286 | +p_seq = df_Germ['Price index (on basis of marks before July 1924, reichsmarks after)'].copy() |
| 287 | +e_seq = 1/df_Germ['Cents per mark'] |
| 288 | + |
| 289 | +lab = ['Price Index', '1/Cents per Mark'] |
| 290 | + |
| 291 | +# create plot |
| 292 | +fig, ax = plt.subplots(figsize=[9,5], dpi=200) |
| 293 | +ax1 = create_plot(p_seq, e_seq, df_Germ.index, lab, ax) |
| 294 | + |
| 295 | +plt.figtext(0.5, 0.0, 'Germany', horizontalalignment='center', fontsize=12) |
| 296 | +plt.show() |
| 297 | +``` |
| 298 | + |
| 299 | +Jiacheng: I add the new graph here. |
| 300 | + |
| 301 | +```python |
| 302 | +p_seq = df_Germ['Price index (on basis of marks before July 1924, reichsmarks after)'].copy() |
| 303 | +e_seq = 1/df_Germ['Cents per mark'].copy() |
| 304 | + |
| 305 | +# adjust the price level/exchange rate after the currency reform |
| 306 | +p_seq[p_seq.index > '06-01-1924'] = p_seq[p_seq.index > '06-01-1924'] * 1e12 |
| 307 | +e_seq[e_seq.index > '12-01-1923'] = e_seq[e_seq.index > '12-01-1923'] * 1e12 |
| 308 | + |
| 309 | +lab = ['Price Index (Marks or converted to Marks)', '1/Cents per Mark (or Reichsmark converted to Mark)'] |
| 310 | + |
| 311 | +# create plot |
| 312 | +fig, ax = plt.subplots(figsize=[10,7], dpi=200) |
| 313 | +ax1 = create_plot(p_seq, e_seq, df_Germ.index, lab, ax) |
| 314 | + |
| 315 | +plt.figtext(0.5, 0.0, 'Germany', horizontalalignment='center', fontsize=12) |
| 316 | +plt.show() |
| 317 | +``` |
| 318 | + |
| 319 | +**Note to Jiacheng:** |
| 320 | + |
| 321 | +There might be some ambiguity about exactly which column in the "balance sheets" of the central bank that we want to interpret as "money". Typically it will be something like "notes" or "total notes" on the liability sides of the balance sheets in the spreadsheet table. We can resolve uncertainties in your mind quickly with a meeting. |
| 322 | + |
| 323 | +**First Steps:** What I'd like you to do as first is to use matplotlib in a Jupyter notebook to take logs of the price level and reproduce pretty versions of our four tables. |
| 324 | + |
| 325 | +**Seecond Steps:** There are some fun additonal things we can plot to set the stage for our cagan_ree and cagan_adaptive notebooks. For example, we have the data to plot logs of real balances around the times of the stabilizations. We can hunt for instances of "velocity dividends". |
| 326 | + |
| 327 | + |
| 328 | +```python |
| 329 | +# import data |
| 330 | +df_fig5 = pd.read_excel('datasets/longprices.xls', sheet_name='all', header=2, index_col=0).iloc[1:] |
| 331 | +df_fig5.index = df_fig5.index.astype(int) |
| 332 | + |
| 333 | +df_fig5.head(5) |
| 334 | +``` |
| 335 | + |
| 336 | +```python |
| 337 | +# create plot |
| 338 | +cols = ['UK', 'US', 'France', 'Castile'] |
| 339 | + |
| 340 | +fig, ax = plt.subplots(1, 1, figsize=[8, 5], dpi=200) |
| 341 | + |
| 342 | +for col in cols: |
| 343 | + ax.plot(df_fig5.index, df_fig5[col]) |
| 344 | + ax.text(x=df_fig5.index[-1]+2, y=df_fig5[col].iloc[-1], s=col) |
| 345 | + |
| 346 | +ax.spines[['right', 'top']].set_visible(False) |
| 347 | +ax.set_yscale('log') |
| 348 | +ax.set_ylabel('Index 1913 = 100') |
| 349 | +ax.set_xlim(xmin=1600) |
| 350 | +ax.set_ylim([10, 1e6]) |
| 351 | +plt.tight_layout() |
| 352 | +plt.show() |
| 353 | +``` |
0 commit comments