From ab5df41ba7e1b95f89c896e74e11c673ddfcfae6 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Wed, 5 Aug 2026 10:09:08 +1000 Subject: [PATCH 1/2] FIX: seven source-side defects found via the translation review Addresses the defects reported in #602, which were surfaced by Copilot's review of the Malayalam translation PRs and traced back to the English source. Code correctness (pandas.md): * replace `type(x) != str` with `not isinstance(x, str)` in both `.map()` examples, so `str` subclasses are treated as strings * replace `np.isnan(x)` with `pd.isna(x)` in `replace_nan`, which tolerates `None`, `pd.NA` and `pd.NaT` where `np.isnan` raises `TypeError` * drop the dead `research.stlouisfed.org` URL from the prose introducing the FRED example; it now names `requests.get(url)`, matching the code cell directly below it Both edited cells were replayed against the lecture's own data: the rendered output and dtypes are byte-identical, so no cached notebook output moves. Typography and naming: * python_by_example.md: use single backticks for the four inline code spans written with triple backticks * functions.md: describe the call stack as a last-in, first-out (LIFO) data structure rather than a "First In Last Out (FILO) queue" * numpy.md: space after the `---` marker at line 218, matching the repo's dominant convention; `Numpy` -> `NumPy`; `discreteRV` -> `DiscreteRV` to match the class actually defined in the cell above Item 6 of #602 is not actioned: `df.query("cc + cg >= 80 & POP <= 20000")` is correct as written. `DataFrame.query` rewrites the `&` token to `and` before parsing, so the expression has boolean precedence and is equivalent to the parenthesised boolean-indexing example above it, as the prose claims. `**Part2**` at numpy.md:1432 is also fixed. It is the sibling of the reported `**Part1**` in the same exercise, and fixing only the reported line would have left the pair inconsistent. Closes #602 Co-Authored-By: Claude Opus 5 (1M context) --- lectures/functions.md | 2 +- lectures/numpy.md | 10 +++++----- lectures/pandas.md | 8 ++++---- lectures/python_by_example.md | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lectures/functions.md b/lectures/functions.md index cdc88059..622910f8 100644 --- a/lectures/functions.md +++ b/lectures/functions.md @@ -451,7 +451,7 @@ What happens here is that each successive call uses it's own *frame* in the *sta * a frame is where the local variables of a given function call are held * stack is memory used to process function calls - * a First In Last Out (FILO) queue + * a last-in, first-out (LIFO) data structure This example is somewhat contrived, since the first (iterative) solution would usually be preferred to the recursive solution. diff --git a/lectures/numpy.md b/lectures/numpy.md index 653ca0fc..1d247cc0 100644 --- a/lectures/numpy.md +++ b/lectures/numpy.md @@ -215,7 +215,7 @@ z See also `np.asarray`, which performs a similar function, but does not make a distinct copy of data already in a NumPy array. -To read in the array data from a text file containing numeric data use `np.loadtxt` ---see [the documentation](https://numpy.org/doc/stable/reference/routines.io.html) for details. +To read in the array data from a text file containing numeric data use `np.loadtxt` --- see [the documentation](https://numpy.org/doc/stable/reference/routines.io.html) for details. @@ -1271,7 +1271,7 @@ you will understand. There is a problem here, however. -Suppose that `q` is altered after an instance of `discreteRV` is +Suppose that `q` is altered after an instance of `DiscreteRV` is created, for example by ```{code-cell} python3 @@ -1406,11 +1406,11 @@ F.plot(ax) :label: np_ex4 ``` -Recall that [broadcasting](broadcasting) in Numpy can help us conduct element-wise operations on arrays with different number of dimensions without using `for` loops. +Recall that [broadcasting](broadcasting) in NumPy can help us conduct element-wise operations on arrays with different number of dimensions without using `for` loops. In this exercise, try to use `for` loops to replicate the result of the following broadcasting operations. -**Part1**: Try to replicate this simple example using `for` loops and compare your results with the broadcasting operation below. +**Part 1**: Try to replicate this simple example using `for` loops and compare your results with the broadcasting operation below. ```{code-cell} python3 @@ -1429,7 +1429,7 @@ tags: [hide-output] print(A) ``` -**Part2**: Move on to replicate the result of the following broadcasting operation. Meanwhile, compare the speeds of broadcasting and the `for` loop you implement. +**Part 2**: Move on to replicate the result of the following broadcasting operation. Meanwhile, compare the speeds of broadcasting and the `for` loop you implement. For this part of the exercise you can use the `tic`/`toc` functions from the `quantecon` library to time the execution. diff --git a/lectures/pandas.md b/lectures/pandas.md index 8218f44d..fac1f41b 100644 --- a/lectures/pandas.md +++ b/lectures/pandas.md @@ -380,7 +380,7 @@ df.apply(update_row, axis=1) ```{code-cell} ipython3 # Round all decimal numbers to 2 decimal places -df.map(lambda x : round(x,2) if type(x)!=str else x) +df.map(lambda x : round(x,2) if not isinstance(x, str) else x) ``` **Application: Missing Value Imputation** @@ -403,8 +403,8 @@ We can use the `.map()` method again to replace all missing values with 0 ```{code-cell} ipython3 # replace all NaN values by 0 def replace_nan(x): - if type(x)!=str: - return 0 if np.isnan(x) else x + if not isinstance(x, str): + return 0 if pd.isna(x) else x else: return x @@ -536,7 +536,7 @@ In the second case, you can either * switch to another machine * solve your proxy problem by reading [the documentation](https://requests.readthedocs.io/en/latest/) -Assuming that all is working, you can now proceed to use the `source` object returned by the call `requests.get('https://research.stlouisfed.org/fred2/series/UNRATE/downloaddata/UNRATE.csv')` +Assuming that all is working, you can now proceed to build the `source` object from the data returned by the call `requests.get(url)` ```{code-cell} ipython3 url = 'https://fred.stlouisfed.org/graph/fredgraph.csv?bgcolor=%23e1e9f0&chart_type=line&drp=0&fo=open%20sans&graph_bgcolor=%23ffffff&height=450&mode=fred&recession_bars=on&txtcolor=%23444444&ts=12&tts=12&width=1318&nt=0&thu=0&trc=0&show_legend=yes&show_axis_titles=yes&show_tooltip=yes&id=UNRATE&scale=left&cosd=1948-01-01&coed=2024-06-01&line_color=%234572a7&link_values=false&line_style=solid&mark_type=none&mw=3&lw=2&ost=-99999&oet=99999&mma=0&fml=a&fq=Monthly&fam=avg&fgst=lin&fgsnd=2020-02-01&line_index=1&transformation=lin&vintage_date=2024-07-29&revision_date=2024-07-29&nd=1948-01-01' diff --git a/lectures/python_by_example.md b/lectures/python_by_example.md index f89c87f5..95d06ece 100644 --- a/lectures/python_by_example.md +++ b/lectures/python_by_example.md @@ -380,9 +380,9 @@ plt.plot(ϵ_values) plt.show() ``` -A while loop will keep executing the code block delimited by indentation until the condition (```i < ts_length```) is satisfied. +A while loop will keep executing the code block delimited by indentation until the condition (`i < ts_length`) is satisfied. -In this case, the program will keep adding values to the list ```ϵ_values``` until ```i``` equals ```ts_length```: +In this case, the program will keep adding values to the list `ϵ_values` until `i` equals `ts_length`: ```{code-cell} python3 i == ts_length #the ending condition for the while loop From bed9f09c03e96fd94bf9604efb840d3edb4d22d7 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Wed, 5 Aug 2026 11:06:34 +1000 Subject: [PATCH 2/2] FIX: correct while-loop semantics and an its/it's typo Two pre-existing prose defects on lines this PR already touches, both raised in Copilot's review of #604 and listed as out-of-scope candidates in the PR description. * python_by_example.md: a while loop runs *as long as* its condition holds, not "until the condition is satisfied", which said the loop starts when the condition is false and stops when it becomes true. The next sentence already described the behaviour correctly, so the two contradicted each other. * functions.md: "each successive call uses it's own frame" -> "its". Prose only; no code cells change. Co-Authored-By: Claude Opus 5 (1M context) --- lectures/functions.md | 2 +- lectures/python_by_example.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lectures/functions.md b/lectures/functions.md index 622910f8..9152f15d 100644 --- a/lectures/functions.md +++ b/lectures/functions.md @@ -447,7 +447,7 @@ def x(t): return 2 * x(t-1) ``` -What happens here is that each successive call uses it's own *frame* in the *stack* +What happens here is that each successive call uses its own *frame* in the *stack* * a frame is where the local variables of a given function call are held * stack is memory used to process function calls diff --git a/lectures/python_by_example.md b/lectures/python_by_example.md index 95d06ece..919770ad 100644 --- a/lectures/python_by_example.md +++ b/lectures/python_by_example.md @@ -380,7 +380,7 @@ plt.plot(ϵ_values) plt.show() ``` -A while loop will keep executing the code block delimited by indentation until the condition (`i < ts_length`) is satisfied. +A while loop will keep executing the code block delimited by indentation as long as the condition (`i < ts_length`) is satisfied. In this case, the program will keep adding values to the list `ϵ_values` until `i` equals `ts_length`: