<jupyter_start><jupyter_text>Cheatsheet!😎  Authors: <NAME> and <NAME>  The Jupyter Notebook How to start a Jupyter notebook1. Open a terminal   - In Windows: press the Windows key, then type `cmd` and press `Enter`.   - On a Mac, type `terminal` in spotlight and press `Enter`.2. Type `jupyter notebook` and press `Enter` CellsThere a two different types of cells:* *Code* cells - in these, you can type programming code (such as Python code)* Text cells (using something called *Markdown*)The cell type can be changed between *Code* and *Markdown* using the dropdown box at the top.   Python 0. Some helpful ideas**Modules**Sometimes we need to add extra bits of functionality to Python which aren't available by default. An example we use here is called the Numpy package. To use the Numpy package, we *import* it, like this:<jupyter_code>import numpy as np<jupyter_output><empty_output><jupyter_text>By typing the `as np` part, we can save ourselves some typing whenever we want to use Numpy later in our code.** Comments **Comments are a way of helping you and other people understand your code. Comments are ignored by Python when your code is evaluated and so you can add explanations of what your code is doing in normal language like this:<jupyter_code># here we assign a variable age to the number 10:
age = 10<jupyter_output><empty_output><jupyter_text>We use the `` symbol to tell Python that the whole line is a comment. Notice also that the Jupyter notebook helpfully changes the colour of comment lines.  **Indentation**In Python, we use indentation to organise different sections of code. In the example below, `print('True')` is part of the `if` statement (see section 4.) and so its execution depends on whether `1 < 4` is true. On the other hand, the  `print('Hello')` statement is independent of the `if` statement and always executes.<jupyter_code>if 1 < 4:
    print('True')
    
print('Hello')<jupyter_output><empty_output><jupyter_text>There are many examples in Python of using a colon `:` followed by an indented block of code. See section 4. (`if` statements), section 5. (`for` loops) and section 6. (Functions). Without indentation, Python will complain! See how this **does not work**:<jupyter_code>if 1 < 4:
print('True')<jupyter_output><empty_output><jupyter_text>** Getting help **You can find the documentation for Python functions by typing the function name, followed by a question mark, like this:<jupyter_code>print?<jupyter_output><empty_output><jupyter_text>If you want to know how to do something in Python, it's always a good idea to search Google.  1. VariablesTake a look at this simple Python code:<jupyter_code>a = 4<jupyter_output><empty_output><jupyter_text>This is called variable assignment. We *assign* the value `4` to the variable named `a`. Practically, variables names are usually more descriptive than a single letter.Variables don't have to be integer numbers, they can have many different types, such as:* decimal numbers (known as floats)* text (known as strings)* True or False (known as booleans)Some examples of using different variable types are below. Here, we are describing some information about a person called Bob. We are also showing the type of the variable after assigning a value to it.<jupyter_code>bob_name = 'Bob'
type(bob_name)
bob_age = 7
type(bob_age)
bob_height = 1.5
type(bob_height)
bob_blue_eyes = True
type(bob_blue_eyes)<jupyter_output><empty_output><jupyter_text>**Testing for equality**Above, we assigned values to some variables using a single equal sign `=`. When we want to check if a variable is equal to something, we use a double equal sign `==` like this:<jupyter_code># Testing for equality with two equal signs
bob_age == 5<jupyter_output><empty_output><jupyter_text>The result from the equality test is either `True` or `False` depending on whether the condition is met, `False` in this case. Notice how this is different to variable assignment, which uses one equal sign.<jupyter_code># Assigning Anna's age to a variable with a single equal sign
anna_age = 5<jupyter_output><empty_output><jupyter_text>2. Lists  A list is another type of variable. Lists are sequences of objects. Here is an example of a list, which we have named `my_list`:<jupyter_code>my_list = [2, 4, 6, 8, 10]
type(my_list)<jupyter_output><empty_output><jupyter_text>Lists are created using square brackets. Commas are used to separate the elements of the list. List elements don't have to all be the same type:<jupyter_code>my_second_list = ['this is a string!', 9.4, True, 18]<jupyter_output><empty_output><jupyter_text>In fact, lists can contain variables which we've previously assigned:<jupyter_code>person_info = [bob_name, bob_age, bob_height, bob_blue_eyes]

print(person_info)<jupyter_output><empty_output><jupyter_text>2.1 Indexing and slicingWe can access the elements of a list by indexing and slicing. To get the first element of a list we do this:<jupyter_code>my_list[0]<jupyter_output><empty_output><jupyter_text>This is called indexing. Notice how indexing starts at zero and not one! If we want multiple elements, we use slicing. Let's say we want the second, third and fourth elements:<jupyter_code>my_list[1:4]<jupyter_output><empty_output><jupyter_text>The `1:4` in the square brackets means get all the elements with indices from `1` (inclusive) to `4` (exclusive). Some more examples of slicing are shown in the table below, where coloured blocks represent the elements we get from each slicing example.`my_list` elementIndexSlicing examples`my_list[1:4]``my_list[0:1]``my_list[2:]``my_list[:3]``my_list[:-2]``my_list[::2]`    2    0                            4    1                            6    2                            8    3                                10    4                            Some things to notice about slicing:* Omitting an index before the colon is the same as using a zero. E.g. `my_list[:3]` is the same as `my_list[0:3]`.* We can use negative indices after the colon to count back from the end of a list.* Slices always return a list, so `my_list[0:1]` is a list with a single element at index `0`.  2.1 Add elements to a listTo add a new element to the end of a list:<jupyter_code>my_list.append('a new element!')
print(my_list)<jupyter_output><empty_output><jupyter_text>2.2 Remove elements from a listTo remove the element with index 3:<jupyter_code>my_list.pop(3)
print(my_list)<jupyter_output><empty_output><jupyter_text>2.3 Finding the length of a list<jupyter_code>len(my_list)<jupyter_output><empty_output><jupyter_text>3. ArraysArrays are like lists, but can be multi-dimensional. A matrix in maths can be considered to be a two-dimensional (2D) array. Here is an example of a 2D array, using the Numpy package (referenced here as `np`) which we previously imported:<jupyter_code>my_array = np.array([[1,2,3], [4,5,6], [7,8,9]])
print(my_array)<jupyter_output><empty_output><jupyter_text>3.1 Indexing and slicingIndexing and slicing works for arrays in the same way as for lists. The only difference is that we use commas to separate each dimension we want to index. For instance, we index a 2D array like this: `my_array[row_index, column_index]`, where `row_index` and `column_index` are each just like the indices (or slices) we used for lists. Rows and columns are indexed like this: ![rowcol](https://www.dropbox.com/s/u6n2yi0me2xye2m/xy-rowcol.png?dl=1)So to get the array element in the first row and third column, we do this:<jupyter_code>my_array[0, 2]<jupyter_output><empty_output><jupyter_text>We can slice arrays just like lists. For instance, to get the first row of the array, the row index would be `0` and the column index would be a slice `0:3` to get all columns.<jupyter_code>my_array[0, 0:3]<jupyter_output><empty_output><jupyter_text>In practice, we can simply use a colon `:` instead of `0:3` to get all elements along a particular dimension:<jupyter_code>my_array[0, :]<jupyter_output><empty_output><jupyter_text>3.2 Adding and removing elements from arraysOnce a Numpy array is created, it's impossible to add or remove elements from it. (There are ways to effectively do this, but generally they are inefficient - Google *array concatenation in numpy*.) Therefore, we tend to first create an array which has the correct size, and then later worry about filling it up with data, as seen in the next sub-section.  3.3 Creating arrays Arrays are always created with a specific size (i.e. number of rows and columns).**An array filled with given data**<jupyter_code>my_data_array = np.array([[5,3,7],[2,7,-1]])
print(my_data_array)<jupyter_output><empty_output><jupyter_text>**An array filled with zeros**This is useful when we know how much data we want to store, but we don't know what it is yet. In this way, we first create an array of zeros and then later populate it when we have the data.<jupyter_code>my_zeros_array = np.zeros((4,3))
print(my_zeros_array)<jupyter_output><empty_output><jupyter_text>**An array filled with ones**<jupyter_code>my_ones_array = np.ones((2, 5))
print(my_ones_array)<jupyter_output><empty_output><jupyter_text>**Specifying data type**All elements in a Numpy array must have the same type. This is different to lists, where elements in the same list can be of different types. For instance, a list could have two elements: an integer and a string, whereas the elements in an array must all be integers or all be floats for example.Let's create an array filled with ones, but let's make sure that the ones are represented as integers, instead of floats which is the default:<jupyter_code>my_integer_array = np.ones((2,5), dtype=int)
print(my_integer_array)<jupyter_output><empty_output><jupyter_text>If we check the type of the array like we did for other variables we notice that the actual type of the elements isn't revealed:<jupyter_code>type(my_integer_array)<jupyter_output><empty_output><jupyter_text>`numpy.ndarray` just means that the variable is a Numpy array. To find the type of the array elements we do:<jupyter_code>my_integer_array.dtype<jupyter_output><empty_output><jupyter_text>3.4 Populating arrays Adding data to an array is simply done like this:<jupyter_code>my_zeros_array[1, :] = [1, 2, 3]
print(my_zeros_array)<jupyter_output><empty_output><jupyter_text>We assign the data to the elements of the array using slicing and indexing. Notice how the data has to have the correct size. In this example, we are populating the three columns in the second row with three numbers.  3.4 Finding the size of an array<jupyter_code>np.shape(my_zeros_array)<jupyter_output><empty_output><jupyter_text>4. `if` statementsSometimes we want our code to make a choice. We use `if` statements to evaluate some code only *if* some condition is true. Let's see an example:<jupyter_code># Check whether Bob is tall enough to ride a rollercoaster or not.

if bob_height > 1.3:
    print('Yay! Bob can have fun on the rollercoaster!')<jupyter_output><empty_output><jupyter_text>In the above example, we first check if Bob's height is greater than 1.3 using the `if` statement with the greater than symbol `>`. If this is true, then we print some text. We can also evaluate some code if the `if` statement is not true. Here's the example again, but with an `else` statement:<jupyter_code>anna_height = 1.2

if anna_height > 1.3:
    print('Yay! You can have fun on the rollercoaster!')
else:
    print('Sorry, you are too short! Maybe next year...')<jupyter_output><empty_output><jupyter_text>We can also be more specific by testing multiple conditions using the `elif` statement:<jupyter_code>anna_height = 1.2

if anna_height > 1.3:
    print('Yay! You can have fun on the rollercoaster!')
elif 1.1 < anna_height < 1.3:
    print('You are too short for the rollercoaster, but have fun on the Teacups!')
else:
    print('Sorry, you are too short! Maybe next year...')<jupyter_output><empty_output><jupyter_text>5. `for` loopsSometimes we want to repeat the same code multiple times. For example, we might want to do the same thing to each element in a list. First, let's look at a simple example of a `for` loop. Let's print each element in a list:<jupyter_code>my_number_list = [0,1,2]
for i in my_number_list:
    print(i)<jupyter_output><empty_output><jupyter_text>This `for` loop is identical to the following code:<jupyter_code>i = my_number_list[0]
print(i)
i = my_number_list[1]
print(i)
i = my_number_list[2]
print(i)<jupyter_output><empty_output><jupyter_text>We can see how the `for` loop is easier to read and type! This is even more true if we want to do something more useful. Let's say we have a list of numbers we want to add together:<jupyter_code>num_list = [10,20,30,40,50,60,70]

total = num_list[0] + num_list[1] + num_list[2] + num_list[3] + num_list[4] + num_list[5] + num_list[6]

print (total)<jupyter_output><empty_output><jupyter_text>If we had a list with 100 elements, imagine how long this would take to type! A better way is to use a `for` loop:<jupyter_code>total = 0
for num in num_list:        # num takes the value of each element in num_list: num = num_list[0]; num = num_list[1] ...
    total = total + num     # this value is added to total, so for the first two steps of  the loop:
                            # total = 0 + num_list[0]
                            # total = 0 + num_list[0] + num_list[1] and so on.

print(total)<jupyter_output><empty_output><jupyter_text>We can understand how the loop works by looking at the table below. Each step of the loop is called an iteration (shown as rows in the table). So, for each iteration the code `total = total + num` is evaluated. The number of iterations is equal to the number of elements in the list `num_list`. Iteration `num``total`010101203023060340100450150560210670280  6. FunctionsIn the examples so far, when we wanted to display some text or a variable, we used the code `print()`. This is an example of a Python function.A function is a block of code that does something specific. We invoke a function (use it) by typing its name followed by parentheses, like this: `function_name()`. Some functions take inputs (these are known as parameters or arguments); these are typed in between the parenthesis, and separated by commas, like this: `function_name(x, y, z)`. In the case of the `print()` function, the input is the text or variable we want to display.Some functions also produce output which can be assigned to variables. For example, the output from the function for finding the size of an array (see section 3.4) can be assigned to a variable:<jupyter_code>array_size = np.shape(my_zeros_array)
print(array_size)<jupyter_output><empty_output><jupyter_text>Here, the function `shape()` is part of the Numpy package, and therefore, we type `np.shape` instead of just `shape()` so Python knows where to find the function. To be clear: `my_zeros_array` is the input argument to the function `shape()`. Python finds the number of rows and columns in the input array and returns the answer, which we assign to a new variable called `array_size`.`print()` is an example of a Python *built-in* function. We can also define our own functions like this:<jupyter_code>def my_func(x):
    return 2 + x

print(my_func(2))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.0823815150321649, 'fraction_numerical': 0.01536037810161481, 'mean_word_length': 5.036053882725832, 'pattern_counts': {'":': 0, '<': 160, '<?xml version=': 0, '>': 159, 'https://': 1, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '38', 'dir': 'jupyter-structured-clean-dedup', 'id': '604374', 'license': 'MIT', 'n_tokens_mistral': 4759, 'n_tokens_neox': 4568, 'n_words': 2001, 'path': '5-Other_useful_notebooks/cheatsheet.ipynb', 'repo_name': 'JQFonseca/computing_materials_science', 'size': '15247'}