Midterm exams

This is a "closed book" examination - in particular, you are not to use any resources outside of this notebook (except possibly pen and paper). You may consult help from within the notebook using ? but not any online references. You should turn wireless off or set your laptop in "Airplane" mode prior to taking the exam.

You have 2 hours to complete the exam.


In [1]:
%matplotlib inline
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

In [2]:
%load_ext rpy2.ipython

Q1 (10 points).

  1. Read the data/iris.csv data set into a Pandas DataFrame. Dispaly the first 4 lines of the DataFrame. (2 points)
  2. Create a new DataFrame showing the mean SepalLength, SepalWidth, PetalLength and PetalWidth for the 3 different types of irises. (4 points)
  3. Make a scatter plot of SepalLength against PetalLength where each species is assigned a different color. (4 points)

In [3]:
df = pd.read_csv('data/iris.csv')
df.head(4)


Out[3]:
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
0 5.1 3.5 1.4 0.2 setosa
1 4.9 3.0 1.4 0.2 setosa
2 4.7 3.2 1.3 0.2 setosa
3 4.6 3.1 1.5 0.2 setosa

In [4]:
df.groupby('Species').mean()


Out[4]:
Sepal.Length Sepal.Width Petal.Length Petal.Width
Species
setosa 5.006 3.428 1.462 0.246
versicolor 5.936 2.770 4.260 1.326
virginica 6.588 2.974 5.552 2.026

In [5]:
sns.lmplot(x='Petal.Length', y='Sepal.Length', hue='Species', data=df, fit_reg=False)
pass


Q2 (10 points)

Write a function peek(df, n) to display a random selection of $n$ rows of any dataframe (without repetition). Use it to show 5 random rows from the iris data set. The function should take as inputs a dataframe and an integer. Do not use the pandas sample method.


In [6]:
def peek(df, n):
    """Display a random selection of n rows of datafraem df."""
    if df.shape[0] < n:
        return df
    idx = np.random.choice(df.shape[0], n)
    return df.iloc[idx]

In [7]:
peek(df, 5)


Out[7]:
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
131 7.9 3.8 6.4 2.0 virginica
10 5.4 3.7 1.5 0.2 setosa
94 5.6 2.7 4.2 1.3 versicolor
123 6.3 2.7 4.9 1.8 virginica
66 5.6 3.0 4.5 1.5 versicolor

Q3 (10 points)

Write a function that when given $m$ vectors of length $k$ and another $n$ vectors of length $k$, returns an $m \times n$ matrix of the cosine distance between each pair of vectors. Take the cosine distance to be $$ \frac{A \cdot B}{\|A\} \|B\|} $$ for any two vectors $A$ and $B$.

Do not use the scipy.spatial.distance.cosine function or any functions from np.linalg or scipy.llnalg.


In [8]:
import numpy as np

In [9]:
def norm(A):
    return np.sqrt(np.sum(A**2))

def cosine_distance(A, B):
    """Cosine distance."""
    return (A @ B)/(norm(A)*norm(B))

In [34]:
A = np.array([1,2,3,4])
B = np.array([2,3,1,4])
cosine_distance(A, B)


Out[34]:
0.90000000000000002

In [38]:
def cosine_distance_matrix(M, N):
    """Cosine distance between each pair of vectors in M and N."""
    m = len(M)
    n = len(N)
    res = np.zeros((m,n))
    for i in range(m):
        for j in range(n):
            res[i, j] = cosine_distance(M[i], N[j])
    return res

In [36]:
M = [A, B]
cosine_distance_matrix(M, M)


<< [1 2 3 4] [1 2 3 4]
<< [1 2 3 4] [2 3 1 4]
<< [2 3 1 4] [1 2 3 4]
<< [2 3 1 4] [2 3 1 4]
Out[36]:
array([[ 1. ,  0.9],
       [ 0.9,  1. ]])

Q4 (10 points)

Consider the following matrix $A$ with dimensions (4,6), to be interpreted as 4 rows of the measurements of 6 features.

np.array([[5, 5, 2, 6, 2, 0],
          [8, 6, 7, 8, 9, 7],
          [9, 5, 0, 4, 6, 8],
          [8, 7, 9, 3, 6, 1]])
  1. Add 1 to the first row, 2 to the second row, 3 to the third row and 4 to the fourth row using a vector v = np.array([1,2,3,4]) and broadcasting. (2 points)
  2. Normalize A so that its row means are all 0 and call it A1. (2 points)
  3. What are the singular values of A1? (2 points)
  4. What are the eigenvalues of the covariance matrix of A1? (2 points)
  5. Find the least squares solution vector $x$ if $Ax = y$ where y = np.array([1,2,3,4]).T (2 points)

In [11]:
A = np.array([[5, 5, 2, 6, 2, 0],
          [8, 6, 7, 8, 9, 7],
          [9, 5, 0, 4, 6, 8],
          [8, 7, 9, 3, 6, 1]])

In [12]:
v = np.array([1,2,3,4]) 
A + v[:, np.newaxis]


Out[12]:
array([[ 6,  6,  3,  7,  3,  1],
       [10,  8,  9, 10, 11,  9],
       [12,  8,  3,  7,  9, 11],
       [12, 11, 13,  7, 10,  5]])

In [13]:
row_means = np.mean(A, axis=1)
A1 = A - row_means[:, np.newaxis]
A1


Out[13]:
array([[ 1.66666667,  1.66666667, -1.33333333,  2.66666667, -1.33333333,
        -3.33333333],
       [ 0.5       , -1.5       , -0.5       ,  0.5       ,  1.5       ,
        -0.5       ],
       [ 3.66666667, -0.33333333, -5.33333333, -1.33333333,  0.66666667,
         2.66666667],
       [ 2.33333333,  1.33333333,  3.33333333, -2.66666667,  0.33333333,
        -4.66666667]])

In [14]:
U, s, V = np.linalg.svd(A1)
s


Out[14]:
array([ 8.31664037,  5.97534743,  4.63524708,  2.26786258])

In [15]:
np.linalg.eigvals(np.cov(A1))


Out[15]:
array([ 13.83330139,   7.14095537,   4.2971031 ,   1.02864013])

In [16]:
y = np.array([1,2,3,4])
x, res, rank, s = np.linalg.lstsq(A, y)
x


Out[16]:
array([ 0.36013647,  0.2088858 ,  0.05653918, -0.33575926,  0.0281829 ,
       -0.01396471])

Q10 (10 points)

We want to calculate the first 100 Catalan numbers. The $n^\text{th}$ Catalan number is given by $$ C_n = \prod_{k=2}^n \frac{n+k}{k} $$ for $n \ge 0$.

  1. Use numpy to find the first 100 Catalan number - the function should take a single argument $n$ and return an array [Catalan(1), Catalan(2), ..., Catalan(n)] (4 points).
  2. Use numba to find the first 100 Catalan numbers (starting from 1) fast using a JIT compilation 4 points)
  3. Use cython to find the first 100 Catalan numbers (starting from 1) fast both AOT compilation (4 points)

In each case, code readability and efficiency is important.


In [17]:
def catalan(n):
    k = np.arange(2, n+1)
    return np.prod((n+k)/k)

def catalan_python(n):
    ans = np.zeros(n)
    for m in range(1, n+1):
        ans[m-1] = catalan(m)
    return ans

In [18]:
from numba import jit

@jit(nopython=True)
def catalan_(n):
    s = 1
    for k in range(2, n+1):
        s *= (n+k)/k
    return s

@jit(nopython=True)
def catalan_numba(n):
    ans = np.zeros(n)
    for m in range(1, n+1):
        ans[m-1] = catalan_(m)
    return ans

In [19]:
%load_ext cython

In [20]:
%%cython -a
cimport cython
import numpy as np

# @cython.cdivision
cdef double catalan(int n):
    cdef double s = 1
    cdef int k

    # s = 1
    for k in range(2, n+1):
        s *= (n+k)/k
    return s

@cython.wraparound(False)
@cython.boundscheck(False)
def catalan_cython(int n):
    cdef int m
    cdef double[:] ans = np.zeros(n)
    
    for m in range(1, n+1):
        ans[m-1] = catalan(m)
    return np.array(ans)


Out[20]:
Cython: _cython_magic_742c545dcc127f352f0b652054aacee3.pyx

Generated by Cython 0.25.2

Yellow lines hint at Python interaction.
Click on a line that starts with a "+" to see the C code that Cython generated for it.

+01: cimport cython
  __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(0, 1, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+02: import numpy as np
  __pyx_t_1 = __Pyx_Import(__pyx_n_s_numpy, 0, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_1) < 0) __PYX_ERR(0, 2, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 03: 
 04: # @cython.cdivision
+05: cdef double catalan(int n):
static double __pyx_f_46_cython_magic_742c545dcc127f352f0b652054aacee3_catalan(int __pyx_v_n) {
  double __pyx_v_s;
  int __pyx_v_k;
  double __pyx_r;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("catalan", 0);
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_WriteUnraisable("_cython_magic_742c545dcc127f352f0b652054aacee3.catalan", __pyx_clineno, __pyx_lineno, __pyx_filename, 0, 0);
  __pyx_r = 0;
  __pyx_L0:;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
+06:     cdef double s = 1
  __pyx_v_s = 1.0;
 07:     cdef int k
 08: 
 09:     # s = 1
+10:     for k in range(2, n+1):
  __pyx_t_1 = (__pyx_v_n + 1);
  for (__pyx_t_2 = 2; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
    __pyx_v_k = __pyx_t_2;
+11:         s *= (n+k)/k
    __pyx_t_3 = (__pyx_v_n + __pyx_v_k);
    if (unlikely(__pyx_v_k == 0)) {
      PyErr_SetString(PyExc_ZeroDivisionError, "float division");
      __PYX_ERR(0, 11, __pyx_L1_error)
    }
    __pyx_v_s = (__pyx_v_s * (((double)__pyx_t_3) / ((double)__pyx_v_k)));
  }
+12:     return s
  __pyx_r = __pyx_v_s;
  goto __pyx_L0;
 13: 
 14: @cython.wraparound(False)
 15: @cython.boundscheck(False)
+16: def catalan_cython(int n):
/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_742c545dcc127f352f0b652054aacee3_1catalan_cython(PyObject *__pyx_self, PyObject *__pyx_arg_n); /*proto*/
static PyMethodDef __pyx_mdef_46_cython_magic_742c545dcc127f352f0b652054aacee3_1catalan_cython = {"catalan_cython", (PyCFunction)__pyx_pw_46_cython_magic_742c545dcc127f352f0b652054aacee3_1catalan_cython, METH_O, 0};
static PyObject *__pyx_pw_46_cython_magic_742c545dcc127f352f0b652054aacee3_1catalan_cython(PyObject *__pyx_self, PyObject *__pyx_arg_n) {
  int __pyx_v_n;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("catalan_cython (wrapper)", 0);
  assert(__pyx_arg_n); {
    __pyx_v_n = __Pyx_PyInt_As_int(__pyx_arg_n); if (unlikely((__pyx_v_n == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 16, __pyx_L3_error)
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L3_error:;
  __Pyx_AddTraceback("_cython_magic_742c545dcc127f352f0b652054aacee3.catalan_cython", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_46_cython_magic_742c545dcc127f352f0b652054aacee3_catalan_cython(__pyx_self, ((int)__pyx_v_n));

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_742c545dcc127f352f0b652054aacee3_catalan_cython(CYTHON_UNUSED PyObject *__pyx_self, int __pyx_v_n) {
  int __pyx_v_m;
  __Pyx_memviewslice __pyx_v_ans = { 0, 0, { 0 }, { 0 }, { 0 } };
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("catalan_cython", 0);
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_XDECREF(__pyx_t_3);
  __Pyx_XDECREF(__pyx_t_4);
  __Pyx_XDECREF(__pyx_t_5);
  __PYX_XDEC_MEMVIEW(&__pyx_t_6, 1);
  __Pyx_AddTraceback("_cython_magic_742c545dcc127f352f0b652054aacee3.catalan_cython", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __PYX_XDEC_MEMVIEW(&__pyx_v_ans, 1);
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_tuple__14 = PyTuple_Pack(4, __pyx_n_s_n, __pyx_n_s_n, __pyx_n_s_m, __pyx_n_s_ans); if (unlikely(!__pyx_tuple__14)) __PYX_ERR(0, 16, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_tuple__14);
  __Pyx_GIVEREF(__pyx_tuple__14);
/* … */
  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_742c545dcc127f352f0b652054aacee3_1catalan_cython, NULL, __pyx_n_s_cython_magic_742c545dcc127f352f); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 16, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_catalan_cython, __pyx_t_1) < 0) __PYX_ERR(0, 16, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_codeobj__15 = (PyObject*)__Pyx_PyCode_New(1, 0, 4, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__14, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_Users_cliburn_ipython_cython__c, __pyx_n_s_catalan_cython, 16, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__15)) __PYX_ERR(0, 16, __pyx_L1_error)
 17:     cdef int m
+18:     cdef double[:] ans = np.zeros(n)
  __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 18, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_zeros); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 18, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_t_2 = __Pyx_PyInt_From_int(__pyx_v_n); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 18, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_4 = NULL;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) {
    __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3);
    if (likely(__pyx_t_4)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
      __Pyx_INCREF(__pyx_t_4);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_3, function);
    }
  }
  if (!__pyx_t_4) {
    __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 18, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    __Pyx_GOTREF(__pyx_t_1);
  } else {
    #if CYTHON_FAST_PYCALL
    if (PyFunction_Check(__pyx_t_3)) {
      PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_t_2};
      __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 18, __pyx_L1_error)
      __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
      __Pyx_GOTREF(__pyx_t_1);
      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    } else
    #endif
    #if CYTHON_FAST_PYCCALL
    if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
      PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_t_2};
      __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 18, __pyx_L1_error)
      __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
      __Pyx_GOTREF(__pyx_t_1);
      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    } else
    #endif
    {
      __pyx_t_5 = PyTuple_New(1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 18, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_5);
      __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_4); __pyx_t_4 = NULL;
      __Pyx_GIVEREF(__pyx_t_2);
      PyTuple_SET_ITEM(__pyx_t_5, 0+1, __pyx_t_2);
      __pyx_t_2 = 0;
      __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_5, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 18, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_1);
      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
    }
  }
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_t_6 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_t_1);
  if (unlikely(!__pyx_t_6.memview)) __PYX_ERR(0, 18, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_v_ans = __pyx_t_6;
  __pyx_t_6.memview = NULL;
  __pyx_t_6.data = NULL;
 19: 
+20:     for m in range(1, n+1):
  __pyx_t_7 = (__pyx_v_n + 1);
  for (__pyx_t_8 = 1; __pyx_t_8 < __pyx_t_7; __pyx_t_8+=1) {
    __pyx_v_m = __pyx_t_8;
+21:         ans[m-1] = catalan(m)
    __pyx_t_9 = (__pyx_v_m - 1);
    *((double *) ( /* dim=0 */ (__pyx_v_ans.data + __pyx_t_9 * __pyx_v_ans.strides[0]) )) = __pyx_f_46_cython_magic_742c545dcc127f352f0b652054aacee3_catalan(__pyx_v_m);
  }
+22:     return np.array(ans)
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 22, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_array); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 22, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_5);
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_t_3 = __pyx_memoryview_fromslice(__pyx_v_ans, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 22, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_2 = NULL;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) {
    __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_5);
    if (likely(__pyx_t_2)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5);
      __Pyx_INCREF(__pyx_t_2);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_5, function);
    }
  }
  if (!__pyx_t_2) {
    __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 22, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __Pyx_GOTREF(__pyx_t_1);
  } else {
    #if CYTHON_FAST_PYCALL
    if (PyFunction_Check(__pyx_t_5)) {
      PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_3};
      __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 22, __pyx_L1_error)
      __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
      __Pyx_GOTREF(__pyx_t_1);
      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    } else
    #endif
    #if CYTHON_FAST_PYCCALL
    if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) {
      PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_3};
      __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 22, __pyx_L1_error)
      __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
      __Pyx_GOTREF(__pyx_t_1);
      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    } else
    #endif
    {
      __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 22, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_4);
      __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2); __pyx_t_2 = NULL;
      __Pyx_GIVEREF(__pyx_t_3);
      PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_t_3);
      __pyx_t_3 = 0;
      __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 22, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_1);
      __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
    }
  }
  __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
  __pyx_r = __pyx_t_1;
  __pyx_t_1 = 0;
  goto __pyx_L0;

In [21]:
catalan_python(10)


Out[21]:
array([  1.00000000e+00,   2.00000000e+00,   5.00000000e+00,
         1.40000000e+01,   4.20000000e+01,   1.32000000e+02,
         4.29000000e+02,   1.43000000e+03,   4.86200000e+03,
         1.67960000e+04])

In [22]:
catalan_cython(10)


Out[22]:
array([  1.00000000e+00,   2.00000000e+00,   5.00000000e+00,
         1.40000000e+01,   4.20000000e+01,   1.32000000e+02,
         4.29000000e+02,   1.43000000e+03,   4.86200000e+03,
         1.67960000e+04])

In [23]:
%timeit ans0 = catalan_python(100)


100 loops, best of 3: 1.98 ms per loop

In [24]:
%timeit ans1 = catalan_numba(100)


The slowest run took 7493.65 times longer than the fastest. This could mean that an intermediate result is being cached.
1 loop, best of 3: 36.8 µs per loop

In [25]:
%timeit ans2 = catalan_cython(100)


10000 loops, best of 3: 53.6 µs per loop