<jupyter_start><jupyter_text>Module 7: Using array operations instead of loops<jupyter_code>import numpy as np<jupyter_output><empty_output><jupyter_text>Example: midpoint calculation  Find the midpoints$$m_i = \frac{1}{2} (a_i + a_{i+1}); \quad 0 \le i < N-1$$<jupyter_code>a = np.arange(6)
a<jupyter_output><empty_output><jupyter_text>Explicit Python loop<jupyter_code>N = len(a)
m = np.zeros(N-1)
for i in range(N-1):
    m[i] = 0.5*(a[i] + a[i+1])
m<jupyter_output><empty_output><jupyter_text>Can we avoid the loop? * `a[i]` covers the elements `[0, 1, 2, 3, 4]`* `a[i+1]` covers the elements `[1, 2, 3, 4, 5]` Can we get these numbers by slicing? * `a[i]` is like `a[:-1]`* `a[i+1]` is like `a[1:]`  Use the sliced arrays<jupyter_code>m = 0.5*(a[:-1] + a[1:])
m<jupyter_output><empty_output><jupyter_text>```[0, 1, 2, 3, 4, 5]   [0, 1, 2, 3, 4, 5]---------------------    +  [1, 3, 5, 7, 9]``` Using sliced arrays is* more readable (more elegant)* faster **Prefered way to work with arrays**  Speed-up<jupyter_code>%%timeit
m = np.zeros(N)
for i in range(N-1):
    m[i] = 0.5*(a[i] + a[i+1])
%%timeit
m = 0.5*(a[:-1] + a[1:])<jupyter_output>2.79 µs ± 61.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
{'fraction_non_alphanumeric': 0.21311475409836064, 'fraction_numerical': 0.05573770491803279, 'mean_word_length': 4.5, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 20, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '199441', 'license': 'MIT', 'n_tokens_mistral': 593, 'n_tokens_neox': 545, 'n_words': 144, 'path': 'Module_7/Module_7_numpy-arrayshifts.ipynb', 'repo_name': 'Py4Physics/PHY194', 'size': '1220'}