argmax, argmin argsort and quick sort | 快速排序

This Saturday class we went over indexing and ordering a group of items by their sorted indices. For those who are more advanced, please go over the section on quick sort.

For example,

>> import numpy as np
>>> packpack =np.array([‘snack’,’book’,’pen’,’eraser’,’apple’])
# Position of the biggest word (alphabetically)
>>> np.argmax(packpack)

[out]: 0
# Position of the smallest word (alphabetically)
>>> np.argmin(packpack)

[out]: 4

# Position of the words if we are to sort them alphabetically
>>> np.argsort(packpack)

[out]: array([4, 1, 3, 2, 0], dtype=int64)

Now let us sort them:
>>> packpack[np.argsort(packpack)]

[out]: array([‘apple’, ‘book’, ‘eraser’, ‘pen’, ‘snack’], dtype='<U6′)

Then we tried sorting numbers:

numbers = np.array([2,3,5,7,1,4,6,15,5,2,7,9,10,15,9,17,12])
>>> numbers[np.argsort(numbers)]

[out]: array([ 1, 2, 2, 3, 4, 5, 5, 6, 7, 7, 9, 9, 10, 12, 15, 15, 17])


Finally we dig deeper: how do you really sort things fast systematically? Using quick sort!

 

Use snippets to code faster | snippet 加速编程

Until NeuralLink or other developments that can help us bypass typing all together, we want to find ways to save ourselves time from typing code.   Using snippet is a must for children, who may not be great at typing.   Here is how to do it in Sublime Test 3 (ST) and Visual Studio Code (code).

Sublime Test:
Tools – > Developer -> New Snippet.

VS Code:
Shift + Control + p

Write the snippet:

Snippets are json files. Use this web app, or some packages, or write json if you prefer to put the code into the json format.

Explaining .json snippet in VS Code:

  • The first set of “” encloses the name of the snippet (call it anything you like).
  • Prefix defines a prefix used in the IntelliSense drop down. For example, if you have a snippet for plotting, you may want to prefix it with “plot”.
  • body is the snippet content.
  • Note that: $1, $2 for tab stops
  • Description is the description.  When you start typing the prefix of a snippet, its description will come up.

Logit transform | 分数对数转换

After we discussed logarithm (‘log’) last week, we explored a bit on some commonly used methods that have log embedded in them.   For example, the logit function, or logit transform (using the “natural” logarithm).   We explained its definition by the following Python code.

>>> epsilon=0.001
>>> def logit(c):
>>>  d = np.log((c+epsilon)/(1+ epsilon-c))
>>>  return d

The following is the inverse, which is to bring what was transformed back to what it was before.

>>> def inverse_logit(a):
>>>  b = ((1+ epsilon)*np.exp(a) – epsilon)/(np.exp(a)+1)
>>>  return b

>> print(logit(0.1)) #-2.1883847407670785
>>> print(inverse_logit(logit(0.1))) #0.09999999999999999

It is much more revealing on what the logit transform is doing by looking at some pictures of how this works.  See how fast when it is transformed!   Why it is stretched instead of being shrunk?  We know that taking log is to do division multiple times (recall log10 of a number is how many times it needs to divide by 10 in order to become 1).     But when it applies to numbers between 0 and 1, it gives us the opposite effect.  A positive small number less than one has to divide by 10 negative times to become 1.  For example, 0.01 needs to be divided by 10 negative two times to be restored to 1.  That’s why you see that y axis we have negatives.

On the other hand, we also have positives in the y-axis.  That’s because about half of the numbers (c+epsilon)/(1+ epsilon-c) (the odds) are large positive numbers.  Play around with it and you will surely get it.

Magic Math Mandarin

>> x = np.linspace(0,1,1000)
>>> y = logit(x)
>>> plt.scatter(x=x, y=y, alpha=0.3)
>>> title =”logit transform”
>>> plt.title(“%s”%title)
>>> plt.xlabel(“numbers between 0 and 1 (inclusive”)
>>> plt.ylabel(“after logit transform”)
>>> plt.xlim(-6, 6)
>>> plt.ylim(-6, 6)
>>> plt.gca().set_aspect(‘equal’, adjustable=’box’)
>>> plt.draw()

Look at the same plot with the axis scaled differently:

Magic Math Mandarin

zero, one and two | 零,一,二

It is not easy for a young child to comprehend multiplication by 1, as how they are taught in school is often the robotic multiplication table.   She or he can very quickly answer mutiplications by 2, or 3.    Because of this, questions like “what is the product of 1,2, 3, 4” (i.e. 4 factorial) can get a wide range of answers because the number “1” confuses the young mind.

Pychologist says that an infant learns the number 2 before the number 1.   And we can see why: with 2, there is something to compare against, like two fingers.  If there is only one finger, there is no variation, it is confusing.

When we teach multiplication, don’t forget to show that math is an integral part of the real world around us.   It is invented to simplify addition.  Multiply by 1 means just the thing itself.  Multiply by 2 means adding two of this thing together.  Multiply by 3 means adding three of the thing together.  The thing can be a bag of candies or the footage of a home.

Finally, we should show children how to use computers (not calculators) to do computations.   While a question like “give me the sum from 1 to 199” can be solved within seconds with math tricks, a slightly different question “give me the product from 1 to 199” won’t work with the same trick.  But if you know how to make the computer do the job, you can still answer it within seconds.

 

Logarithm | 对数

As we had explored in previous classes, division is subtraction again and again and again, multiplication is adding again and again.  Exponentiation is multiply again and again and again— They are all inventions to simplify repeated computation.

So is the invention of logarithm: taking log is division again and again and again.   They were invented by John Napier who was a Scottish mathematician, physicist, and astronomer  in 1614 as a means to simplify calculations.

🙂 Today’s  Python numpy class summary:

Log10 means how many times divide by 10 will return you to 1. log10(100) will give you 2 because 100 divide by 10 twice returns us to one.
>>> np.log10(100)
One trillion divide by 10 twelve times returns it to 1.
>>> np.log10(1000000000000)

>>> np.linspace(0.0, 3.0, num=4)
Out: array([0., 1., 2., 3.])

>>> np.logspace(0.0, 3.0, num=4)
Out: array([   1.,   10.,  100., 1000.])

>>> np.linspace(0.0, 12.0, num=13)
Out: array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.])
>>> np.logspace(0.0, 12.0, num=13)
Out: array([1.e+00, 1.e+01, 1.e+02, 1.e+03, 1.e+04, 1.e+05, 1.e+06, 1.e+07, 1.e+08, 1.e+09, 1.e+10, 1.e+11, 1.e+12])

Bonus:  Did you know that Engineers and scientists used to use a tool called “slide rule” (计算尺) to do logarithmic computations until 1970s when electronic computer and calculators came into use.  You should go and check it out if any of your grandparents have one of these.

Find if something is also somewhere else (contd) | 找一找那里是不是也有

Today’s class we continued the game of finding matches.  We expanded from numbers to names.

Let’s pretend that there is a room out there that has the following famous people:

room1 = pd.Series([‘Grace Hopper’, ‘Albert Einstein’,’Michael Faraday’,’Emmy Noether’,’Ada Lovelace’])

And another room with these famous people:

room2 = pd.Series([‘Isaac Newton’, ‘Thomas Edison’,’Mary Somerville’,’Matilda’,’Ada Lovelace’])

These two rooms are in building:

building = pd.concat([room1, room2], axis=1)

building.columns= [‘room1′,’room2’]

             room1            room2
0     Grace Hopper     Isaac Newton
1  Albert Einstein    Thomas Edison
2  Michael Faraday  Mary Somerville
3     Emmy Noether          Matilda
4     Ada Lovelace     Ada Lovelace

Now we want to find a list of people “who” in the building and the rooms.

who = np.array([‘Albert Einstein’,’Michael Faraday’,’Ada Lovelace’])

Are they in room 1?

np.isin(who, room1)
Out: array([ True,  True,  True])

Are they in room2?

np.isin(who, room2)

Out: array([False, False,  True])

Are they in the building?

np.isin(who, building)
Out: array([ True,  True,  True])

We are constantly comparing things.  How to compare is a very tricky and interesting subject.  You should look up the source code of the function in1d and see how it does it.

Find if something is also somewhere else | 找一找那里是不是也有

In today’s class we played a game: finding the numbers in a group that are also in another group. As usual, we started simple using numpy (np).   Here is the summary:

score1 = np.array([0, 1, 3, 5, 10,3])

score2 = np.array([2,3])

We use the inld function from numpy to do the matching and counting:
np.in1d(score1,score2)

score1[np.in1d(score1,score2)]

Our result is:

array([3, 3])

There is another way to do this:

np.array([item in score2 for item in score1])

array([False, False,  True, False, False,  True])

score1[np.array([item in score2 for item in score1])]

will give you exactly the same answer.   Try it.

For very large groups of numbers or words, what we’ve just learned will work just as well.

Please practice and turn in the homework.

Count non-zeros using numpy.count_nonzero | 数非零数

Today our class practiced making the computer count number of non-zero numbers using the numpy library from Python.  This can be useful if you have a ton of numbers.

import numpy as np; import pandas as pd

some_array = np.array([[0,1,7,0,0],[3,0,0,2,19]])

array([[ 0,  1,  7,  0,  0],
[ 3,  0,  0,  2, 19]])

np.count_nonzero(some_array)

5

np.count_nonzero(some_array,  axis=0)  Count across the rows, i.e. count along the column

array([1, 1, 1, 1, 1], dtype=int64)

np.count_nonzero(some_array,  axis=1)  Count across the columns, i.e. count along the row

array([2, 3], dtype=int64)

We talked about this example:

d = {'Basket1': [3, 0], 'Basket2': [3, 4]}
df = pd.DataFrame(data=d, index=['Apple','Chips'])

# Count the number of non-zeros across the rows
pd.Series(np.count_nonzero(df, axis=0), index=df.columns.tolist())

This was the result we got.

Basket1    1
Basket2    2
dtype: int64

That was a very tiny data. If we have a dataset with a million rows and columns, we should definitely do this!

GitHub repo vs gist

  • For sharing snippets 代码片段 (secret or public), use gist. Gist keeps all revision history without making a fuss. No tickets or pull requests. Note: secret is not private, but you would need the url to access, unlike public gists.
  • For projects that want publicity and open collaboration, use something like GitHub repo.

Saving Ipython script history

%save sessionName linesToKeep

This will save script in line numbers you specify in linesToKeep,for example, 1-20 34-50 64 into a file called “sessionName.py” in your current working directory.

If you are not so specific on which lines you want to keep, you can save everything.

%save sessionName ~0/

This saves everything from the current session, denoted as “~0″ into file “sessionName.py” in your cwd (current working directory).

%save pastSession ~1/

This saves everything from the past session, denoted as “~1” into file “pastSession.py” in your cwd.