<jupyter_start><jupyter_text>Intro to Numpy Objectives- Make new NumPy arrays- Perform arithmetic with arrays- Use common array methods and NumPy functions- Filter arrays using boolean arrays and "fancy" indexing<jupyter_code># add the "as np" so we don't have to type "numpy" each time
import numpy as np<jupyter_output><empty_output><jupyter_text>Making ArraysAt the beginning of the Python lesson we loaded data into NumPy from a text file.Let's look at a few other ways to make arrays.If you've got data in Python lists those can be converted to arrays:<jupyter_code># list like yesterday
odds = [1, 3, 5, 7]
odds
# pass the list to np.array
odds_arr = np.array(odds)
odds_arr<jupyter_output><empty_output><jupyter_text>Lists and arrays have some similarities:<jupyter_code>print('index', odds[1], odds_arr[1])
print('slice', odds[1:3], odds_arr[1:3])
print('length', len(odds), len(odds_arr))
for x in odds:
    print(x)
for x in odds_arr:
    print(x)<jupyter_output><empty_output><jupyter_text>But some things are different:  QuestionHow would you add 1 to every number in the `odds` list and make a new list with those (even) numbers? (You don't need to write code, isntead talk about how you'd do this.)<jupyter_code>evens = []
for x in odds:
    y = x + 1
    evens.append(y)
evens<jupyter_output><empty_output><jupyter_text>With arrays this is simpler:<jupyter_code>even_arr = odds_arr + 1
even_arr<jupyter_output><empty_output><jupyter_text>Now suppose we want to add these odd and even numbers together. With lists that's another loop, but with arrays:<jupyter_code>even_arr + odds_arr<jupyter_output><empty_output><jupyter_text>Suppose we did need to loop over an array to perform a complex calculation and then store the result in a new array. We can't append to arrays, they have a fixed size.<jupyter_code>odds_arr.append(9)<jupyter_output><empty_output><jupyter_text>We need to create the new array with the appropriate size and shape. (By the way, you can check the size and shape of an array with the `.size` and `.shape` attributes.)Functions for creating new arrays of same given shape are `np.empty`, `np.ones`, `np.zeros`, and `np.arange`. The one thing you *have* to tell these functions is how big the array needs to be.<jupyter_code>np.ones(5)
np.zeros((3, 3))<jupyter_output><empty_output><jupyter_text>QuestionsWhy did I put an extra pair of parentheses in the call to `np.zeros`?Which shape value is for the number of rows in the array, and which is for the number of columns?<jupyter_code>np.zeros((4, 2))<jupyter_output><empty_output><jupyter_text>`np.arange` doesn't take a shape, instead it takes start, stop, and step values to make an array of numbers that cover some range:<jupyter_code>r = np.arange(0, 20, 2)
r<jupyter_output><empty_output><jupyter_text>See even more functions for making arrays at http://docs.scipy.org/doc/numpy/reference/routines.array-creation.html.  Array Methods and NumPy Functions We're going to load some specialy prepared precipitation data derived from the `precip_yearly.csv` file. It's saved in a special cross-platform NumPy binary format. Learn more about NumPy's special binary array storage format at http://docs.scipy.org/doc/numpy/reference/routines.io.html.<jupyter_code>store = np.load('mean_ca_precip.npz')
years = store['years']
precip = store['precip']
print(years)
print(precip)<jupyter_output><empty_output><jupyter_text>Arrays have methods attached to them for doing calculations and transformations with data. For example you can get the mean of an array (as seen with Pandas):<jupyter_code>precip.mean()<jupyter_output><empty_output><jupyter_text>And the NumPy package (`np`) has functions that work on arrays, e.g. to calculate a logarithm:<jupyter_code>np.log(precip)<jupyter_output><empty_output><jupyter_text>Exercise 1Use IPython's tab completion feature to compare available array methods (e.g. `precip.mean`) with available NumPy functions (e.g. `np.log`). Do you notice any differences? There are a massive number of routines in NumPy. For more info see http://docs.scipy.org/doc/numpy/reference/ufuncs.htmlavailable-ufuncs and http://docs.scipy.org/doc/numpy/reference/routines.html.  Boolean Indexing Let's examine which years had more than average precipitation and which had below average.First we'll need the average precipitation:<jupyter_code>avg = precip.mean()<jupyter_output><empty_output><jupyter_text>Then we can compare that average to the values in the `precip` array:<jupyter_code>precip > avg<jupyter_output><empty_output><jupyter_text>The comparison creates a new array of boolean (True/False) values that is True where the precipitation that year was above average and False where the precipitation was below average.We can use the boolean arrays to pull values out of other arrays:<jupyter_code>above = precip > avg
print(precip[above])
print(years[above])<jupyter_output><empty_output><jupyter_text>You can use boolean indexing without first assigning them to an array:<jupyter_code>years[precip < avg]<jupyter_output><empty_output><jupyter_text>But if you do have a boolean array and what its opposite you can use the `~` operator:<jupyter_code>years[~above]<jupyter_output><empty_output><jupyter_text>We can also use boolean indexing to make assignments to arrays:<jupyter_code>arr = np.random.normal(size=(4, 4))
arr
arr[arr < 0] = 0
arr<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09084153817573844, 'fraction_numerical': 0.005201560468140442, 'mean_word_length': 6.197860962566845, 'pattern_counts': {'":': 0, '<': 79, '<?xml version=': 0, '>': 79, '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': '19', 'dir': 'jupyter-structured-clean-dedup', 'id': '209868', 'license': 'CC-BY-4.0', 'n_tokens_mistral': 1770, 'n_tokens_neox': 1688, 'n_words': 608, 'path': 'scientific_python/NumPy.ipynb', 'repo_name': 'elliewix/2016-01-28-uiuc-swc', 'size': '5383'}