Table of contents

- Printing Elements of a List
- Constructing a For Loop to Print Elements of a List
- Using a For Loop and a Numerical Vector
- Using a For Loop and a Numerical Vector to Calculate exp
- Using a For Loop within a Matrix
- Using a For Loop to Check if a Magic Square is "Magic"
- Using a For Loop and a Numerical Vector to Calculate exp within a Pandas DataFrame
- Using a For Loop to Plot from a NumPy Array (Not Complete)
- Using a For Loop to Plot from a DataFrame (Not Complete)
- Using a For Loop with Enumerate to label Points on a Scatter Plot (Not Complete)

## Printing Elements of a List

Let's first create a list of words.

Now let's assume we want to perform an operation on each word in the list, in this case let's look at something simple like printing out the value of the word. We can do this manually by indexing into a. For example we can index into the 0th element:

`apple`

Then the first element:

`banana`

The second element:

`cake`

`doughnut`

Notice how we repeated the statement four times, with only the index changing. In our case we ran the command four times going from the 0th to 4th index (0 order indexing, up to 4 but excluding 4 itself):

## Constructing a For Loop to Print Elements of a List

This can also be done with a loop. Constructing the loop is very similar to how one would write in English. First of all we have the variable a, which is a list of words. Next to begin a loop, we begin the line with for and then set a loop variable through to loop through, in this case we can call this loop variable each_word and then we must define the list a that we are wanting to examine. Once done we have done this we end the line in a colon. In Python the commands that are ran in the loop are indented underneigh the loop using the default convention of 4 spaces (to indent and revert indentation we can also use the tab and inverse tab – shift and tab). In this case we will print each_word in the list a:

```
apple
banana
cake
doughnut
```

Note we called the loop variable each_word so "for each_word in a:" read in a similar manner to the English sentence "for each word in the list a". We can instead define the loop variable under another name, for example by using the letter e:

```
apple
banana
cake
doughnut
```

Okay so we can make our loop more complicated and tell it to print a string as well as the word from the list e.

```
apple
string
banana
string
cake
string
doughnut
string
```

If we compare this to:

```
apple
banana
cake
doughnut
string
```

We can see that the last line, line 4 is not included in the loop and so is only ran once. In Python indenting by the correct number of spaces is important when it comes to loops.

## Using a For Loop and a Numerical Vector

We can repeat the above using a numeric vector opposed to a list of words, for example:

```
0
1
2
3
4
5
```

We can also perform mathematical operations for example we can initialise a variable total before the for loop and set it to 0 and then calculate the sum of total and each number in the numerical list as we go through it:

`final total = 15`

To see what is going on in more detail we can add additional print statements.

```
before loop
total = 0
start of loop
loop iteration
number = 0
old total = 0
new total = 0
loop iteration
number = 1
old total = 0
new total = 1
loop iteration
number = 2
old total = 1
new total = 3
loop iteration
number = 3
old total = 3
new total = 6
loop iteration
number = 4
old total = 6
new total = 10
loop iteration
number = 5
old total = 10
new total = 15
after loop
final total = 15
```

Recall that we can use the function range to create an equally spaced numeric list. So the above can be replaced by:

```
before loop
total = 0
start of loop
loop iteration
number = 0
old total = 0
new total = 0
loop iteration
number = 1
old total = 0
new total = 1
loop iteration
number = 2
old total = 1
new total = 3
loop iteration
number = 3
old total = 3
new total = 6
loop iteration
number = 4
old total = 6
new total = 10
loop iteration
number = 5
old total = 10
new total = 15
after loop
final total = 15
```

Once again recalling that Python using zero order indexing, therefore the numerical list starts from 0 and goes up to 6 in integer steps but does not reach 6, so the last value is 5.

The list can also be specified as a NumPy array using the arange function:

```
before loop
total = 0
start of loop
loop iteration
number = 0
old total = 0
new total = 0
loop iteration
number = 1
old total = 0
new total = 1
loop iteration
number = 2
old total = 1
new total = 3
loop iteration
number = 3
old total = 3
new total = 6
loop iteration
number = 4
old total = 6
new total = 10
loop iteration
number = 5
old total = 10
new total = 15
after loop
final total = 15
```

This makes it easy to modify the loop to start at 1 instead of 0 and use step sizes of 2.

```
before loop
total = 0
start of loop
loop iteration
number = 1
old total = 0
new total = 1
loop iteration
number = 3
old total = 1
new total = 4
loop iteration
number = 5
old total = 4
new total = 9
after loop
final total = 9
```

## Using a For Loop and a Numerical Vector to Calculate exp

For a process with 100 % return during a single growth period the rateofgrowth will equal to:

In other words after 1 growth period with 100 % growth you get your starting investment value of 1 plus an additional value of 1 return. This gives 1+1=2.

For a process with 100 % return split during two growth periods the rateofgrowth will equal to:

In the first of the two growth periods you will have your initial investment of 1, plus an additional value of 0.5 return. This means you start the second growth period with 1.5 and then after the second growth period you gain an additional value of 0.75 return. Thus you end up with your starting investment of 1 plus an additional value of 1.25. In other words, we have the additional terms here which make the value greater than 2:

After three growth periods:

If instead you get an investment of 100 % growth over three growth periods, in the first of the three growth periods you will have your initial investment of 1, plus an addition value of 0.3333 return. In the second growth period you thus start with 1.3333 and get 0.4444 return and this means in the third growth period, you start with 1.7778 and get 0.5926 in return. Thus you end up with your starting investment of 1 plus an additional value of 1.3704.

The following can be calculated for integer values between 1 and 10 using a For Loop.

```
i = 1
rateofgrowth = 2.0
i = 2
rateofgrowth = 2.25
i = 3
rateofgrowth = 2.37037037037037
i = 4
rateofgrowth = 2.44140625
i = 5
rateofgrowth = 2.4883199999999994
i = 6
rateofgrowth = 2.5216263717421135
i = 7
rateofgrowth = 2.546499697040712
i = 8
rateofgrowth = 2.565784513950348
i = 9
rateofgrowth = 2.5811747917131984
i = 10
rateofgrowth = 2.5937424601000023
```

It is with higher values of i, that the function for the exponential is supposed to converge, instead of looping through integer steps of i=1 to 10 let's instead create j=10**i giving 10,100,1000…

```
i = 1
j = 10
rateofgrowth = 2.5937424601000023
i = 2
j = 100
rateofgrowth = 2.7048138294215285
i = 3
j = 1000
rateofgrowth = 2.7169239322355936
i = 4
j = 10000
rateofgrowth = 2.7181459268249255
i = 5
j = 100000
rateofgrowth = 2.7182682371922975
i = 6
j = 1000000
rateofgrowth = 2.7182804690957534
i = 7
j = 10000000
rateofgrowth = 2.7182816941320818
i = 8
j = 100000000
rateofgrowth = 2.7182817983473577
i = 9
j = 1000000000
rateofgrowth = 2.7182820520115603
i = 10
j = 1410065408
rateofgrowth = 2.7182817181556262
```

Here the last value of j is wrong, this is a consequence of both i and j being int32 with the number of values of int32 being 2**32=4294967296, these are split between positive and negative values giving plus minus 2147483648 however a value must be taken to also account for 0 which gives 2147483647. In our case the value that j should be 10000000000 exceeds this upper limit and the value yielded is a value calculated in mid calculation. i is taken from the numeric_list as int32:

To rectify this, we can convert it to an int (64 Bit) using the int function:

```
i = 1
j = 10
rateofgrowth = 2.5937424601000023
i = 2
j = 100
rateofgrowth = 2.7048138294215285
i = 3
j = 1000
rateofgrowth = 2.7169239322355936
i = 4
j = 10000
rateofgrowth = 2.7181459268249255
i = 5
j = 100000
rateofgrowth = 2.7182682371922975
i = 6
j = 1000000
rateofgrowth = 2.7182804690957534
i = 7
j = 10000000
rateofgrowth = 2.7182816941320818
i = 8
j = 100000000
rateofgrowth = 2.7182817983473577
i = 9
j = 1000000000
rateofgrowth = 2.7182820520115603
i = 10
j = 10000000000
rateofgrowth = 2.7182820532347876
```

As we see, i and j are now both int (64 Bit) opposed to int32 and there is no problem.

The rate of growth value is seen to converge at higher values of j as expected.

`2.718281828459045`

## Using a For Loop within a Matrix

Let's assume we have a data set like the following. We have 3 experiments and each experiment is ran for 3 trials for each person and there are 3 people. Let's assume we want to find the total score per person per experiment. How would we do this?

The data above can be created using:

Let's first simply the problem and instead of creating the sum of the three trials for each experiment, let's just create an output matrix which has only the data from trial 0:

```
[1 2 3]
[10 11 12]
[19 20 21]
[[ 1 2 3]
[10 11 12]
[19 20 21]]
```

While this works it is tedious to create this manually, let's look at a better way. First of all let's try and see if we can a repeating pattern:

```
[1 2 3]
[10 11 12]
[19 20 21]
[[ 1 2 3]
[10 11 12]
[19 20 21]]
```

Next can we relate index to the original dimensions of the matrix? We can obtain these using the function shape:

```
9
3
```

Here the number of rows is 9. We are working on adding every 3 row and not interested in the number of columns at present. We'll notice that:

```
[0 1 2 3 4 5 6 7 8]
[0 3 6]
```

Let's break down the problem first and simplify it. To the left hand side we have our output matrix with indexes [0,1,2] and to the right hand side we have our original data matrix with indexes i=[0,3,6].

Lets only look at the index of the right hand side:

```
i= 0
i= 3
i= 6
```

We must find first figure out how [0,1,2] relate to i which is [0,3,6]. It is immediately obvious by our definition of every three rows that the index of m in terms of i is i/3. Let's set j to equal i/3.

```
i= 0
j= 0.0
i= 3
j= 1.0
i= 6
j= 2.0
```

However here we see that j is a float instead of an integer as desired. We can rectify this by using the int function:

```
i= 0
j= 0
i= 3
j= 1
i= 6
j= 2
```

With this we can have a look at the problem in terms of indexing the output matrix m and input matrix data by i only:

Okay now lets look at creating the dimensions of m using the dimensions of data:

```
nrows= 9
ncols= 3
allrows= [0 1 2 3 4 5 6 7 8]
everythreerows= [0 3 6]
m= [[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
```

We can now create a loop to prescribe m for integer values of i divided by 3 to data for values of i:

```
nrows= 9
ncols= 3
allrows= [0 1 2 3 4 5 6 7 8]
everythreerows= [0 3 6]
m= [[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
loop
m= [[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
m= [[1. 2. 3.]
[0. 0. 0.]
[0. 0. 0.]]
m= [[ 1. 2. 3.]
[10. 11. 12.]
[ 0. 0. 0.]]
after loop
m= [[ 1. 2. 3.]
[10. 11. 12.]
[19. 20. 21.]]
```

We can now look at how to get a matrix of all the Trial 1 data and a matrix of all the Trial 2 data:

To get the Trial 1 data we can index into data using i+1 opposed to i or i+0:

Updating line 21:

```
nrows= 9
ncols= 3
allrows= [0 1 2 3 4 5 6 7 8]
everythreerows= [0 3 6]
m= [[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
loop
m= [[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
m= [[4. 5. 6.]
[0. 0. 0.]
[0. 0. 0.]]
m= [[ 4. 5. 6.]
[13. 14. 15.]
[ 0. 0. 0.]]
after loop
m= [[ 4. 5. 6.]
[13. 14. 15.]
[22. 23. 24.]]
```

To get the Trial 2 data we can index using i+2:

Updating Line 21 again:

```
nrows= 9
ncols= 3
allrows= [0 1 2 3 4 5 6 7 8]
everythreerows= [0 3 6]
m= [[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
loop
m= [[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
m= [[7. 8. 9.]
[0. 0. 0.]
[0. 0. 0.]]
m= [[ 7. 8. 9.]
[16. 17. 18.]
[ 0. 0. 0.]]
after loop
m= [[ 7. 8. 9.]
[16. 17. 18.]
[25. 26. 27.]]
```

Now we can have a look at the problem at hand, where we don't just want the sub matrices of Trial 0, Trial 1 and Trial 2 but we want the sum of the three Trials per person per experiment:

This can of course just be done by modifying line 21 to include the sum of Trial 0, Trial 1 and Trial 2:

This of course gives us the result we are looking for.

```
nrows= 9
ncols= 3
allrows= [0 1 2 3 4 5 6 7 8]
everythreerows= [0 3 6]
m= [[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
loop
m= [[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
m= [[12. 15. 18.]
[ 0. 0. 0.]
[ 0. 0. 0.]]
m= [[12. 15. 18.]
[39. 42. 45.]
[ 0. 0. 0.]]
after loop
m= [[12. 15. 18.]
[39. 42. 45.]
[66. 69. 72.]]
```

However notice the repetition on the right hand side of line 21:

This can be incorporated into an additional for loop. If we specify everythreerowsminor we can set an outer loop index of j:

We can print

```
nrows= 9
ncols= 3
allrows= [0 1 2 3 4 5 6 7 8]
everythreerows= [0 3 6]
everythreerowsminor= [0 1 2]
m= [[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
loop
m= [[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
after inner loop
m= [[1. 2. 3.]
[0. 0. 0.]
[0. 0. 0.]]
after inner loop
m= [[ 1. 2. 3.]
[10. 11. 12.]
[ 0. 0. 0.]]
after inner loop
after outer loop
m= [[ 1. 2. 3.]
[10. 11. 12.]
[19. 20. 21.]]
after inner loop
m= [[ 5. 7. 9.]
[10. 11. 12.]
[19. 20. 21.]]
after inner loop
m= [[ 5. 7. 9.]
[23. 25. 27.]
[19. 20. 21.]]
after inner loop
after outer loop
m= [[ 5. 7. 9.]
[23. 25. 27.]
[41. 43. 45.]]
after inner loop
m= [[12. 15. 18.]
[23. 25. 27.]
[41. 43. 45.]]
after inner loop
m= [[12. 15. 18.]
[39. 42. 45.]
[41. 43. 45.]]
after inner loop
after outer loop
m= [[12. 15. 18.]
[39. 42. 45.]
[66. 69. 72.]]
```

This code can be easily modified to find every four rows in an updated matrix with 4 experiments and 4 people:

```
nrows= 16
ncols= 4
allrows= [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]
everyfourrows= [ 0 4 8 12]
everyfourrowsminor= [0 1 2 3]
m= [[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
loop
m= [[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
after inner loop
m= [[1. 2. 3. 4.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
after inner loop
m= [[ 1. 2. 3. 4.]
[17. 18. 19. 20.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]
after inner loop
m= [[ 1. 2. 3. 4.]
[17. 18. 19. 20.]
[33. 34. 35. 36.]
[ 0. 0. 0. 0.]]
after inner loop
after outer loop
m= [[ 1. 2. 3. 4.]
[17. 18. 19. 20.]
[33. 34. 35. 36.]
[49. 50. 51. 52.]]
after inner loop
m= [[ 6. 8. 10. 12.]
[17. 18. 19. 20.]
[33. 34. 35. 36.]
[49. 50. 51. 52.]]
after inner loop
m= [[ 6. 8. 10. 12.]
[38. 40. 42. 44.]
[33. 34. 35. 36.]
[49. 50. 51. 52.]]
after inner loop
m= [[ 6. 8. 10. 12.]
[38. 40. 42. 44.]
[70. 72. 74. 76.]
[49. 50. 51. 52.]]
after inner loop
after outer loop
m= [[ 6. 8. 10. 12.]
[ 38. 40. 42. 44.]
[ 70. 72. 74. 76.]
[102. 104. 106. 108.]]
after inner loop
m= [[ 15. 18. 21. 24.]
[ 38. 40. 42. 44.]
[ 70. 72. 74. 76.]
[102. 104. 106. 108.]]
after inner loop
m= [[ 15. 18. 21. 24.]
[ 63. 66. 69. 72.]
[ 70. 72. 74. 76.]
[102. 104. 106. 108.]]
after inner loop
m= [[ 15. 18. 21. 24.]
[ 63. 66. 69. 72.]
[111. 114. 117. 120.]
[102. 104. 106. 108.]]
after inner loop
after outer loop
m= [[ 15. 18. 21. 24.]
[ 63. 66. 69. 72.]
[111. 114. 117. 120.]
[159. 162. 165. 168.]]
after inner loop
m= [[ 28. 32. 36. 40.]
[ 63. 66. 69. 72.]
[111. 114. 117. 120.]
[159. 162. 165. 168.]]
after inner loop
m= [[ 28. 32. 36. 40.]
[ 92. 96. 100. 104.]
[111. 114. 117. 120.]
[159. 162. 165. 168.]]
after inner loop
m= [[ 28. 32. 36. 40.]
[ 92. 96. 100. 104.]
[156. 160. 164. 168.]
[159. 162. 165. 168.]]
after inner loop
after outer loop
m= [[ 28. 32. 36. 40.]
[ 92. 96. 100. 104.]
[156. 160. 164. 168.]
[220. 224. 228. 232.]]
```

This can be simplified by specifying n=4 at line 9 and then replacing every subsequent occurrence of four with n and every 4 with n:

```
import numpy as np
data=np.arange(start=1,stop=65,step=1)
data=np.reshape(data,[16,4])
[nrows,ncols]=np.shape(data)
print('nrows=',nrows)
print('ncols=',ncols)
n=4
allrows=np.arange(start=0,stop=nrows)
print('allrows=',allrows)
everynrows=np.arange(start=0,stop=nrows,step=n)
print('everynrows=',everynrows)
everynrowsminor=np.arange(start=0,stop=n,step=1)
print('everynrowsminor=',everynrowsminor)
#initialisation
m=np.zeros(int(nrows/n)*ncols)
m=np.reshape(m,[int(nrows/n),ncols])
print('m=',m)
print('loop')
for k in everynrowsminor:
for i in everynrows:
print('m=',m)
m[int(i/n),:]=m[int(i/n),:]+data[i+k,:]
print('after inner loop')
print('after outer loop')
print('m=',m)
```

This mean that line 9 can be modified to quickly sum every 2 lines, 3 lines, 4 lines, … and applied to a matrix with differing dimensions. For example changing line 2 and 3 to generate a larger data with 16 rows and 5 rows and modifying line 9 to n=2, to find a matrix which is the sum of every two line:

```
nrows= 16
ncols= 5
allrows= [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]
everynrows= [ 0 2 4 6 8 10 12 14]
everynrowsminor= [0 1]
m= [[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]
loop
m= [[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]
after inner loop
m= [[1. 2. 3. 4. 5.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]
after inner loop
m= [[ 1. 2. 3. 4. 5.]
[11. 12. 13. 14. 15.]
[ 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0.]]
after inner loop
m= [[ 1. 2. 3. 4. 5.]
[11. 12. 13. 14. 15.]
[21. 22. 23. 24. 25.]
[ 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0.]]
after inner loop
m= [[ 1. 2. 3. 4. 5.]
[11. 12. 13. 14. 15.]
[21. 22. 23. 24. 25.]
[31. 32. 33. 34. 35.]
[ 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0.]]
after inner loop
m= [[ 1. 2. 3. 4. 5.]
[11. 12. 13. 14. 15.]
[21. 22. 23. 24. 25.]
[31. 32. 33. 34. 35.]
[41. 42. 43. 44. 45.]
[ 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0.]]
after inner loop
m= [[ 1. 2. 3. 4. 5.]
[11. 12. 13. 14. 15.]
[21. 22. 23. 24. 25.]
[31. 32. 33. 34. 35.]
[41. 42. 43. 44. 45.]
[51. 52. 53. 54. 55.]
[ 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0.]]
after inner loop
m= [[ 1. 2. 3. 4. 5.]
[11. 12. 13. 14. 15.]
[21. 22. 23. 24. 25.]
[31. 32. 33. 34. 35.]
[41. 42. 43. 44. 45.]
[51. 52. 53. 54. 55.]
[61. 62. 63. 64. 65.]
[ 0. 0. 0. 0. 0.]]
after inner loop
after outer loop
m= [[ 1. 2. 3. 4. 5.]
[11. 12. 13. 14. 15.]
[21. 22. 23. 24. 25.]
[31. 32. 33. 34. 35.]
[41. 42. 43. 44. 45.]
[51. 52. 53. 54. 55.]
[61. 62. 63. 64. 65.]
[71. 72. 73. 74. 75.]]
after inner loop
m= [[ 7. 9. 11. 13. 15.]
[11. 12. 13. 14. 15.]
[21. 22. 23. 24. 25.]
[31. 32. 33. 34. 35.]
[41. 42. 43. 44. 45.]
[51. 52. 53. 54. 55.]
[61. 62. 63. 64. 65.]
[71. 72. 73. 74. 75.]]
after inner loop
m= [[ 7. 9. 11. 13. 15.]
[27. 29. 31. 33. 35.]
[21. 22. 23. 24. 25.]
[31. 32. 33. 34. 35.]
[41. 42. 43. 44. 45.]
[51. 52. 53. 54. 55.]
[61. 62. 63. 64. 65.]
[71. 72. 73. 74. 75.]]
after inner loop
m= [[ 7. 9. 11. 13. 15.]
[27. 29. 31. 33. 35.]
[47. 49. 51. 53. 55.]
[31. 32. 33. 34. 35.]
[41. 42. 43. 44. 45.]
[51. 52. 53. 54. 55.]
[61. 62. 63. 64. 65.]
[71. 72. 73. 74. 75.]]
after inner loop
m= [[ 7. 9. 11. 13. 15.]
[27. 29. 31. 33. 35.]
[47. 49. 51. 53. 55.]
[67. 69. 71. 73. 75.]
[41. 42. 43. 44. 45.]
[51. 52. 53. 54. 55.]
[61. 62. 63. 64. 65.]
[71. 72. 73. 74. 75.]]
after inner loop
m= [[ 7. 9. 11. 13. 15.]
[27. 29. 31. 33. 35.]
[47. 49. 51. 53. 55.]
[67. 69. 71. 73. 75.]
[87. 89. 91. 93. 95.]
[51. 52. 53. 54. 55.]
[61. 62. 63. 64. 65.]
[71. 72. 73. 74. 75.]]
after inner loop
m= [[ 7. 9. 11. 13. 15.]
[ 27. 29. 31. 33. 35.]
[ 47. 49. 51. 53. 55.]
[ 67. 69. 71. 73. 75.]
[ 87. 89. 91. 93. 95.]
[107. 109. 111. 113. 115.]
[ 61. 62. 63. 64. 65.]
[ 71. 72. 73. 74. 75.]]
after inner loop
m= [[ 7. 9. 11. 13. 15.]
[ 27. 29. 31. 33. 35.]
[ 47. 49. 51. 53. 55.]
[ 67. 69. 71. 73. 75.]
[ 87. 89. 91. 93. 95.]
[107. 109. 111. 113. 115.]
[127. 129. 131. 133. 135.]
[ 71. 72. 73. 74. 75.]]
after inner loop
after outer loop
m= [[ 7. 9. 11. 13. 15.]
[ 27. 29. 31. 33. 35.]
[ 47. 49. 51. 53. 55.]
[ 67. 69. 71. 73. 75.]
[ 87. 89. 91. 93. 95.]
[107. 109. 111. 113. 115.]
[127. 129. 131. 133. 135.]
[147. 149. 151. 153. 155.]]
```

## Using a For Loop to Check if a Magic Square is "Magic"

Previously a Magic Square was used to practice indexing into a NumPy array. For more details see below:

Running the script above gives the following results:

```
[[17 24 1 8 15]
[23 5 7 14 16]
[ 4 6 13 20 22]
[10 12 19 21 3]
[11 18 25 2 9]]
[17 24 1 8 15]
65
[23 5 7 14 16]
65
[ 4 6 13 20 22]
65
[10 12 19 21 3]
65
[11 18 25 2 9]
65
[17 23 4 10 11]
65
[24 5 6 12 18]
65
[ 1 7 13 19 25]
65
[ 8 14 20 21 2]
65
[15 16 22 3 9]
65
[17 5 13 21 9]
65
[15 14 13 12 11]
65
```

Notice the repetition in lines 15 to 34 and 37 to 56. These can instead be replaced by a for loop. Line 8-20, here we gather the dimensions of the magic square, then create a rowsum vector using these dimensions and initialise it to zero. Then we can create a for loop and assign the sum of each row to this vector. We then repeat the same process for colsum. Then we can later express rowsum and colsum explicitly as a column and row vector respectively.

```
[[17 24 1 8 15]
[23 5 7 14 16]
[ 4 6 13 20 22]
[10 12 19 21 3]
[11 18 25 2 9]]
rowsum = [[65.]
[65.]
[65.]
[65.]
[65.]]
colsum = [[65. 65. 65. 65. 65.]]
sum diag = 65
sum antidiag = 65
```

Note with the way this code is setup, a magic square of size 9 can be tested simply by changing 5 to 9 in line 4:

```
[[47 58 69 80 1 12 23 34 45]
[57 68 79 9 11 22 33 44 46]
[67 78 8 10 21 32 43 54 56]
[77 7 18 20 31 42 53 55 66]
[ 6 17 19 30 41 52 63 65 76]
[16 27 29 40 51 62 64 75 5]
[26 28 39 50 61 72 74 4 15]
[36 38 49 60 71 73 3 14 25]
[37 48 59 70 81 2 13 24 35]]
rowsum = [[369.]
[369.]
[369.]
[369.]
[369.]
[369.]
[369.]
[369.]
[369.]]
colsum = [[369. 369. 369. 369. 369. 369. 369. 369. 369.]]
sum diag = 369
sum antidiag = 369
```

Note when constructing for loops it is sometimes worth testing for loops using a small amount of data, 3 to 5 rows and columns to check that the loop is working before applying it to a much larger dataset.

Randomly generated data can be used in place of the magic square s.

As we can see this random square matrix is not a magic square. The values of the sum of each row, column and diagonals differ.

```
[[ 6 1 4]
[ 4 8 10]
[ 4 6 3]]
rowsum = [[11.]
[22.]
[13.]]
colsum = [[14. 15. 17.]]
sum diag = 17
sum antidiag = 16
```

## Using a For Loop and a Numerical Vector to Calculate exp within a Pandas DataFrame

It is worth revisiting the exponential and having a look at how to save the results to a dataframe opposed to printing in the command window.

Looking at line 17, recall that to select a column within a dataframe use dot indexing i.e. type in the name of the dataframe followed by a . and then the column name. Note in order to index in this manner the column names should not have spaces, the underscore _ should instead be used. Once the column is selected, the row of that column can be indexed numerically by using square brackets.

Note the creation of the Index (Row) names in the DataFrame can also be made using a For Loop. In this case we must convert the numpy array numeric list which can only store numbers to a list which can store numbers and letters we can use the function tolist to do this (line 7). Once it is a list, we can loop through the loop variable listindex for each item in the numeric_list (line 8). Note on the the left handside (line 9) listindex-1 is used because the numeric_list starts at 1 and ends at 11 (goes up to 11 but doesn't reach 11) and we are using 0 order indexing to index into indexnames. To the right hand side because it is a list, we can use 'R' and add the string of listindex to it. Once we have created this, this can be incorporated into the DataFrame during it's creation/initialisation (lines 11-15).

## Using a For Loop to Plot from a NumPy Array (Not Complete)

Let's first create some data using a for loop. Here we want the 0th column of data to be an array from 0 to 10 in steps of 1. The 1st column will be this column to the power of 1, the 2nd column will be this to the power of 2 and the third column will be this to the power of 3.

It is possible to plot the data by indexing each column in alldata

Notice the repetition in lines 2 to 4, it is possible to combine these into a for loop. In this case we are using 0 order indexing but the 0th column is the common x data used in each plot. Therefore in plotnumber we start at 1 and go up to 4 but don't include 4:

## Using a For Loop to Plot from a DataFrame (Not Complete)

To create a plot using the column name, one indexes using square brackets:

From the dataframe one can get the index of the column names of the dataframe by using:

`Index(['x', 'data_1', 'data_2', 'data_3'], dtype='object')`

Then one can index into the index of column names to return the column name:

```
x
data_1
```

Therefore the following line of code:

Can be expressed as:

And this expression can be used in a for loop:

One can also select colours using a for loop:

We can also specify the line style using a for loop:

If instead of having the three plots in the same figure, we wanted a seperate figure for each, this can also be done using a for loop: