<jupyter_start><jupyter_text>NumpyAs described at https://numpy.org  > NumPy is the fundamental package for scientific computing with Python. It contains among other things:> - a powerful N-dimensional array object> - sophisticated (broadcasting) functions> - tools for integrating C/C++ and Fortran code> - useful linear algebra, Fourier transform, and random number capabilitiesIf you are familiar with Matlab, this comparison might be useful:https://docs.scipy.org/doc/numpy/user/numpy-for-matlab-users.html Resources1. Ch 4 in Python for Data Analysis, 2nd Ed, <NAME> (UCalgary library and https://github.com/wesm/pydata-book)2. Ch 2 in Python Data Science Handbook, <NAME> (Ucalgary library and https://github.com/jakevdp/PythonDataScienceHandbook)Let's explore some of the features. First, import Numpy<jupyter_code>import numpy as np<jupyter_output><empty_output><jupyter_text>Create numpy arraysHere are several ways how to create numpy arrays```python>>> np.zeros((3,4))>>> np.ones((2,3,4),dtype=np.int16) >>> d = np.arange(10,25,5)>>> np.linspace(0,2,9)```<jupyter_code># start-stop and number of values evenly spaced
np.linspace(0,2,9)
# start-stop(excluded) and increment
d = np.arange(10,25,5)
d<jupyter_output><empty_output><jupyter_text>Additionally, arrays can be generated from python lists<jupyter_code>a = np.array([1, 2, 3, 4])
a<jupyter_output><empty_output><jupyter_text>Random arraysSometimes it is handy to generate arrays with random entries, just for testing.The numpy.random module has many useful functions. To get help on numpy functions or modules you can use:```pythonnp.info(np.random)```Of course, python `help()` or jupyter `?` will work too. Another nice trick is `tab` for tab completion, and `shift-tab` twice to get info on function parameters<jupyter_code># what is in random
np.info(np.random)<jupyter_output>========================
Random Number Generation
========================

Use ``default_rng()`` to create a `Generator` and call its methods.

=============== =========================================================
Generator
--------------- ---------------------------------------------------------
Generator       Class implementing all of the random number distributions
default_rng     Default constructor for ``Generator``
=============== =========================================================

============================================= ===
BitGenerator Streams that work with Generator
--------------------------------------------- ---
MT19937
PCG64
Philox
SFC64
============================================= ===

============================================= ===
Getting entropy to initialize a BitGenerator
--------------------------------------------- ---
SeedSequence
============================================= ===


Legacy
------

For backwards compatibility with previous ver[...]<jupyter_text>**Use a seed**. It is good practice to set the seed of the random generator so that everytime you run the cell, the same numbers are generated. It makes debugging a lot easier.Now lets generate a matrix with random integers [0, 10) of size 5x4 with `randint()`, and a python list with 10 random entries from a list of strings containing 'low', 'medium', 'high' with `choice()`. Another useful function is `shuffle()`, try it out too.<jupyter_code>np.random.seed(1992)
A = np.random.randint(low=0, high=10, size=(5,4))
A
np.random.seed(1995)
labels = np.random.choice(['low', 'medium', 'high'], size=10)
labels<jupyter_output><empty_output><jupyter_text>IndexingGet the shape of an array rows x columns<jupyter_code>A.shape<jupyter_output><empty_output><jupyter_text>The first row is (zero indexing)<jupyter_code>A[0]<jupyter_output><empty_output><jupyter_text>The first column is<jupyter_code>A[:,0]<jupyter_output><empty_output><jupyter_text>Slicing works too, how would you get the last two rows?<jupyter_code>A[-2:,:]<jupyter_output><empty_output><jupyter_text>Array mathNumpy can handle element-wise math directly, for example converting celcius to fahrenheit<jupyter_code>B = (9/5) * A + 32
B<jupyter_output><empty_output><jupyter_text>Two arrays of same shape can be added etc.<jupyter_code>A + B<jupyter_output><empty_output><jupyter_text>Or we can apply a math function to each element<jupyter_code>np.sin(A)<jupyter_output><empty_output><jupyter_text>Array manipulationIt is often useful to concatenate or stack arrays. This is similar to Matlab<jupyter_code>np.info(np.hstack)
C = np.hstack((A, B))
C
C.shape
D = np.vstack((A, B))
D<jupyter_output><empty_output><jupyter_text>Elements in an array can be modified, either as single elements or entire rows/columns.  Let's create a copy first.<jupyter_code>A_t = np.copy(A)
A_t
A_t[0,0] = 10
A_t
A_t[-1, :] = -1
A_t
A_t[-1, -2:] = [5, 5]
A_t<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.21159057744423598, 'fraction_numerical': 0.016677089847821555, 'mean_word_length': 5.206985769728331, 'pattern_counts': {'":': 0, '<': 58, '<?xml version=': 0, '>': 75, 'https://': 4, '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': '14', 'dir': 'jupyter-structured-clean-dedup', 'id': '363915', 'license': 'MIT', 'n_tokens_mistral': 1500, 'n_tokens_neox': 1422, 'n_words': 444, 'path': 'notebooks/numpy.ipynb', 'repo_name': 'jhua0211/ml-intro', 'size': '4812'}