Pandas Into

I’ve recently been playing with the pandas Python data analysis framework while reading the Python for Data Analysis book (which is written by the author of the pandas library). Here are 2 of my iPython Notebooks that demonstrate some of the basics:

And here’s a little screenshot of what it looks like in iPython Notebook:

ipython notebook screenshot

Reddit Facebook Plusone Twitter Digg Delicious Email

Finding the Golden Ratio

I recently was exploring the Golden Ratio. I was really surprised what a simple (and recursive) relationship it comes from:

golden_ratio

Here is an iPython Notebook explaining the derivation: Golden Ratio iPython Notebook

If you don’t want to look at the iPython Notebook, here is some Python code to find the golden ratio using Fixed-point Iteration:

reduce(lambda acc,_: (acc+1.0)/acc, xrange(100), 1)
# Result: 1.6180339887498947
Reddit Facebook Plusone Twitter Digg Delicious Email

Running Ubuntu on VirtualBox in Windows

I’m mostly a Mac user and I also really like Linux (especially Ubuntu), but I hate Windows. However, I’m occasionally required to use Windows at work, so I’ve found a way to make using Windows more enjoyable: to use Ubuntu (installed on VirtualBox inside of Windows) instead of Windows for everything except for the few tasks which require Windows.

So I have made this little How to Install Ubuntu on VirtualBox in Windows setup guide:

Continue reading “Running Ubuntu on VirtualBox in Windows” »

Reddit Facebook Plusone Twitter Digg Delicious Email

Pyknon Intro, Chords, and Intervals

I’ve continued on my (hopefully) short-term fascination with music+math (it’s fun, but really bad for productivity). So I found this great library for generating music in Python called Pyknon. And it can be installed using pip: pip install pyknon.

I wrote a little python script just to help me understand some concepts in music theory like intervals and chords. It is meant to be read top to bottom (which is why I intersperse functions and variables throughout). It is NOT written in good modular form (in general, I don’t recommend writing python like this). This code can also be used as an intro to the pyknon library.

Behold:

from pyknon.genmidi import Midi
from pyknon.music import NoteSeq, Note, Rest
 
####### First we'll generate all piano notes
 
# Pyknon dubs C5 as the value 0, so Note(0) give you C5
# (C in the 5th octave).  So we have to move 51 keys to the
# left to get the far left key on a piano.
first_note = Note("A,,,,,") # The far-left key on the piano
 
def key_number(n):
    return n.octave * 12 + n.value - first_note.value
 
def note_from_key_number(k):
    return Note(k - 51)
 
def intervals(notes):
    interval = []
    for n in range(len(notes)-1):
        interval.append(notes[n+1] - notes[n])
    return interval
 
piano_notes = map(note_from_key_number, range(88))
midi = Midi(1, tempo=80)
midi.seq_notes(piano_notes, track=0)
midi.write("piano_keys.mid")
 
####### Next we'll examine a major and minor scale, and look at the intervals between
####### each of their notes
 
middle_c = Note("C,")     # key_number=39
note_nums = map(key_number, piano_notes)
print "All piano notes:", note_nums
print "Middle C key number:", key_number(middle_c)
 
# A, means drop the octave, C' means raise the octave.
# Also, in a NoteSeq, Pyknon stays in the same octave unless explicitly
# changed by using either , or '.
C_major = NoteSeq("C D E F G A B C'' ")
A_minor = NoteSeq("A, B C' D E F G A")
 
# Note, when defining a NoteSeq, all notes are by default in the same 
# octave as the starting note.
print "C major (staring with middle C):", map(key_number, NoteSeq("C, D E F G A B"))
print "C major:", map(key_number, C_major)
print "Intervals for C major:", intervals(map(key_number, C_major))
print "A minor:", map(key_number, A_minor)
print "Intervals A minor:", intervals(map(key_number, A_minor))
 
####### Last we'll generate some chords in a major and minor keys.
 
def major_chord(root):
    root_key_num = key_number(root)
    return map(note_from_key_number, [root_key_num, root_key_num+4, root_key_num+7])
 
def minor_chord(root):
    root_key_num = key_number(root)
    return map(note_from_key_number, [root_key_num, root_key_num+3, root_key_num+7])
 
def dim_chord(root):
    root_key_num = key_number(root)
    return map(note_from_key_number, [root_key_num, root_key_num+3, root_key_num+6])
 
# Chord qualities: M m m M M m d (M)
major_chord_progression = [major_chord, minor_chord, minor_chord, major_chord, \
                           major_chord, minor_chord, dim_chord]
 
# Chord qualities: m d M m m M M (m)
minor_chord_progression = [minor_chord, dim_chord, major_chord, minor_chord, \
                           minor_chord, major_chord, major_chord]
 
####### Generate C major chords ###
C_maj_chords = []
for i in range(len(major_chord_progression)):
    C_maj_chords.append(major_chord_progression[i](C_major[i]))
 
# Throw a "mistake" in there to hear the difference
C_maj_chords.append([Note("C"), Note("F#"), Note("Bb")])
 
print "C major chords:", C_maj_chords
 
midi = Midi(1, tempo=80)
midi.seq_chords(map(NoteSeq, C_maj_chords))
midi.write("c_major_chords.mid")
 
####### Generate G minor chords ###
G_minor = NoteSeq("G, A Bb C' D Eb F")
G_min_chords = []
for i in range(len(minor_chord_progression)):
    G_min_chords.append(minor_chord_progression[i](G_minor[i]))
print "G minor chords:", G_min_chords
 
midi = Midi(1, tempo=80)
midi.seq_chords(map(NoteSeq, G_min_chords))
midi.write("g_minor_chords.mid")

And here is the output (excluding the MIDI files it writes):

localhost:music caleb$ python piano_notes.py 
All piano notes: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87]
Middle C key number: 39
C major (staring with middle C): [39, 41, 43, 44, 46, 48, 50]
C major: [51, 53, 55, 56, 58, 60, 62, 63]
Intervals for C major: [2, 2, 1, 2, 2, 2, 1]
A minor: [48, 50, 51, 53, 55, 56, 58, 60]
Intervals A minor: [2, 1, 2, 2, 1, 2, 2]
C major chords: [[<C>, <E>, <G>], [<D>, <F>, <A>], [<E>, <G>, <B>], [<F>, <A>, <C>], [<G>, <B>, <D>], [<A>, <C>, <E>], [<B>, <D>, <F>], [<C>, <F#>, <A#>]]
G minor chords: [[<G>, <A#>, <D>], [<A>, <C>, <D#>], [<A#>, <D>, <F>], [<C>, <D#>, <G>], [<D>, <F>, <A>], [<D#>, <G>, <A#>], [<F>, <A>, <C>]]
Reddit Facebook Plusone Twitter Digg Delicious Email

Music Theory and Math Notes

For the last day, I’ve done some reading on music theory (trying to understand why things are the way they are in terms of math).  Here are my raw unedited notes:

  • Important musical ratios:
    • Unison: 1:1 frequency
    • Octave: 2:1 frequency
      • 12 semitone increase
    • Fifth: 3:2 frequency (i.e. multiply by 1.5)
      • 7 semitone increase
    • Semitone: 2**(1./12) (12th root of 2) – about 1.059 – this is the “half-step” distance, so you can multiply the frequency of F by 1.059 to get the frequency for F#
  • Chromatic scale: 12 notes (list of all semitones in an octave)
  • Diatomic scale: 7 notes
  • To be in a “key” (like C-major) means to select 7 notes from the 12 notes in the chromatic scale
    • In theory, these notes sound good together
  • C-major is the white keys on the piano staring on C
  • There is no E# or B# notes on the piano (because the notes in the diatonic scale are determined by going up fifths).  So the interval between the white keys (which don’t have a black key in between them) are half-tones (i.e. “semitones”).  Each key increase is a “half tone” increase (including black keys).
    • <See python program below to generate chromatic scale>
  • Major key intervals can be derived by starting on C and hitting 7 white key
    • Intervals: whole whole half whole whole whole half
  • Minor key intervals can be derived by starting on A and hitting 7 white keys
    • Intervals: whole half whole whole half whole whole
  • Chords
    • Major chord ratios: 4:5:6
      • The original note
      • A major 3rd
      • A perfect fifth (notice that 4 * 1.5 = 6)
    • Minor chord ratios: 10:12:15
      • The original note
      • A minor 3rd
      • A perfect fifth (notice that 10 * 1.5 = 15)
    • In a “key”, there are 7 chords (numbered I, II, III, IV, V, VI, VII).
      • To determine if which chords (major or minor) are in a key, start at each of the 7 notes in the key and see which chords “fit” into that key (all notes in the chords must be in the key as well).

Python to generate the 12 basic notes (starting with the note F1 = 43.65Hz):

>>> notes = []
>>> acc = f1
>>> for i in range(12):
...     notes.append(acc)
...     acc = acc * 1.5
...
>>> notes
[43.65, 65.475, 98.21249999999999, 147.31875, 220.97812499999998, 331.46718749999997, 497.20078125, 745.8011718749999, 1118.7017578124999, 1678.05263671875, 2517.0789550781246, 3775.618432617187]
>>> note_names = ['f', 'c', 'g', 'd', 'a', 'e', 'b', 'f#', 'c#', 'g#', 'd#', 'a#']
>>> 3729 * 1.5
5593.5
>>> 5593.5 / f1
128.1443298969072
>>> # f8 should equal 5587 Hz. So from A#, if we go up a fifth, we are at F8,
>>> # which is a 7 octaves higher than F1 (2^7 = 128).  128* F1 = F8.

Sources

 

 

Reddit Facebook Plusone Twitter Digg Delicious Email

Reduce with Python and Clojure

I was just playing around writing an annuity calculator function. Here is my first version:

def calculate_annuity(years, interest=0, addition_per_year=0, starting_amount=0):
    result = []
    running_total = starting_amount
    for year in range(years+1):
        result.append(running_total)
        running_total = (running_total + addition_per_year) * (1 + interest)
    return result

Here is a 2nd version, written using reduce instead of a loop:

def calculate_annuity2(years, interest=0, addition_per_year=0, starting_amount=0):
    return reduce(lambda result,addition: result + [(result[-1] + addition) * (1 + interest)],
                  [addition_per_year] * years, [starting_amount])

And here is a version in Clojure (basically a direct translation of the Python one:

(defn annuity [years interest addition_per_year init]
    (reduce
        #(conj %1 (* (+ (last %1) %2) (+ 1 interest)))
        [starting_amount]
        (for [i (range years)] addition_per_year)))

Here are some example use cases:

; Find investment returns by year for a $1000 investment at 7% interest
; for 10 years.
(println (annuity 10 0.07 0 1000))
 
; Find annuity value if contributing $1000 each month and starting with $7777
; with 10% interest for 10 years.
(println (annuity 10 0.10 1000 7777))
 
; Find annuity value if contributing $1000 each month and starting with $777
; with 10% interest for 10 years.
(println (annuity 10 0.07 0 1000))
 
; Test perpetuity annuity that pays out $6000 per year, given a $100000
; at 6.4% interest.
(println (annuity 30 0.064 -6000 100000))
Reddit Facebook Plusone Twitter Digg Delicious Email