It’s not a big leap; it’s one small step. There’s only a little to pick up and there’s not a huge difference in use or functionality. The difference is so small you can switch and just google any conversion issues you have: they’re so small you’ll have no trouble finding the appropriate functions/syntax.

There is a wrapper package in Python with the aim of providing a Matlab-like interface that is well suited for numerical linear algebra. This package is called pylab and wraps NumPy, SciPy and matplotlib. When I use pylab, this is how similar my Python and Matlab code is:

# PYTHON                        | % MATLAB
from pylab import *             | clc; clear all; close all
                                |
# matrix multiplication         | % matrix multiplication
A = rand(3, 3)                  | A = rand(3, 3);
A[0:2, 1] = 4                   | A(1:2, 2) = 4;
I = A @ inv(A)                  | I = A * inv(A);
I = A.dot(inv(A))               |
                                |
# vector manipulations          | % vector manipulations
t = linspace(0, 4, num=1e3)     | t = linspace(0, 4, 1e3);
y1 = cos(t/2) * exp(-t)         | y1 = cos(t/2) .* exp(-t);
y2 = cos(t/2) * exp(-5*t)       | y2 = cos(t/2) .* exp(-5*t);
                                |
# plotting                      | % plotting
figure()                        | figure; hold on
plot(t, y1, label='Slow decay') | plot(t, y1)
plot(t, y2, label='Fast decay') | plot(t, y2)
legend(loc='best')              | legend('Slow decay', 'Fast decay')
show()                          |

Python even has a matrix multiplication operator! Python 3.5 introduces the matrix multiplication operator @ detailed in PEP 465. Python is remarkably well suited for developing numerical algorithms – what else does Python offer?

It turns out that Python is a general programming language built by computer engineers that happens to have a scientific stack built on top of it. This means it’s been optimized to be easy to develop in; the same is not true for Matlab, a domain-specific language.

Here’s a quick overview of some benefits:

  • Functions are simple (a big deal!) They are easy to implement and can be in the same file as a general script (a feature Matlab lacks). This can make your code modular and readable. I mean, in Python functions can even have optional arguments, the scoping just works and functions can be passed as proper variables.
  • Package install is simple, via the pip command line tool. Just pip install python-drawnow to install after you google “matlab python drawnow” and find python-drawnow!
  • Python just works. Some little goodies that are really nice to have and examples of Pythonic code:
  • Documentation in Python is simple, via docstrings.
  • Python has an active development community. Want to change a package you’re using? Make a pull request! Go to a conference or a local Python group!
  • Python is free as in beer and free as in speech. There aren’t any licensing issues and you can see the source code of every function called.
  • clc; clear all; close all; found in Matlab is gone forever! And no more semicolon!

While Matlab is convenient software for linear algebra, it is a language developed by mathematicians. Python has a similar linear algebra interface but is developed by computer scientists which makes it easy to develop in. For a complete discussion of this, see Python, machine learning, and language wars: a highly subjective point of view

In fact, Python is so wonderful there’s even a relevant XKCD1 that illustrates how wonderful Python is a general programming language! But now let’s get down to business describing how to switch over.

Outline for the rest of this post

How to switch to Python

Want to try Python without installing anything? Go to try.jupyter.org or DataJoy to try Python out! (careful – as of 2015-11-3, @ is not yet available for these online tools!)

  1. Install Anaconda with Python 3.5 (and the Anaconda install is easy – it includes everything you’ll need and puts a Launcher.app on your desktop with access to Spyder and IPython notebook!)
  2. Open up Spyder which tries to provide a Matlab-like IDE environment (variable explorer, debugger, etc).
  3. Type from pylab import * which provides a Matlab-like programming environment.
  4. Done! A Matlab-like environment exists. Try almost any function from Matlab to see if it exists in pylab; it probably does.

Resources

Little hints

  • %reset, an IPython magic will clear all variables from the IPython kernel and will restart the current session.
  • If I want the transpose of a matrix, I use A.T, not transpose(A).
  • I use A.shape to get the number of rows and columns of a matrix as (m, n). Not size(A)!
  • * is element-wise multiplication. @ or A.dot(x) is a matrix multiplication
  • Python operates by reference (explanation). This can mean that y = x can fail; any changes to y or x will be reflected in both x and y. This is not the critical bug is seems to be – I’m just careful around plain copy statements. Why?
    • Any operation (e.g., y = 1*x, y = x + 0) avoid this as a reference to 1*x is passed to y.
    • Both ndarray.copy for NumPy and the copy module for everything else exist.
    • Function arguments are passed by argument (source); if this copy issue happens inside a function, it can’t touch values outside the function.
  • reshape(arange(3*3), (3, 3)) can become arange(3*3).reshape(3, 3). To see what else can provide this function mapping from b(a()) to a().b(), go to IPython’s console and type x = a() <RETURN> x.<TAB> and see what pops up.
  • In IPython, the output of Out[n] is accessible through _n at the prompt (i.e., _7 has the same output as Out[7]).
  • List comprehension, enumerate and zip make for loops super easy

Anecdote

Before we get started diving into some details, I would like to share what I heard Rob Nowak say in personal conversation. He’s a senior professor and one of the people that inspired this post. He shared the below on 2016-10-22. He says it only took him two hours to get up to speed and said “there is little barrier to transition”.

I had a Matlab script that performed Lasso. I wanted to implement this in Python, and it only took me two hours.

First, I asked my grad students what to install and they recommend Anaconda. Then I googled “python least squares” to get the basics, then Lasso is not much from this, only some thresholding and shrinkage.

But my data was in a .mat file, so I googled “python load mat file” and found some function [note: scipy.io.loadmat]

Details

Install

The full scientific stack of software is available in Anaconda. Go to their website and download the Python 3.5 version. This gives you many packages but namely it gives you the main scientific stack (matplotlib, scipy, numpy, pandas). Anaconda includes over 330 libraries and it simplifies the entire installation process to a simple .pkg installer.

After navigating to Anaconda’s downloads page, you’re presented with a choice between Python 2 and Python 3. This might seem like a small difference but Python 3 is not backwards-compatible with Python 2. For basic stuff as shown, it doesn’t matter but can play a role when depending on third party packages. I think at this point, I recommend to install Python 3 (and others recommend Python 3 as well).

Development environment

Python aligns with the Unix philospopy: you can choose a Python prompt and you can choose your editor. I have chosen vim as my editor and IPython console as my prompt, but for prompts you can choose among the default python, ipython, bpython or ptpython consoles. IPython is (by far) the most mature and they are most connected with the scientific community. It has even spawned an offspring Project Jupyter that generalizes the IPython notebook/etc to any programming language.

If you prefer an integrated develop environment or IDE, I would most strongly recommend Spyder as it tries to provide a Matlab-like experience. Spyder comes with the Anaconda package and is available in the Python Launcher if you installed Anaconda (on your Desktop). Though I most recommend Spyder for IDEs, other options exist: rodeo, IDLE, NetBeans and PyCharm.

I personally use vim and the IPython console and use the IPython’s magic function %run <file> at the prompt. This means that the prompt can see the variables inside my script – I can just type plot(x); show() at the prompt to see what x looks like. The same feature feature is available in Spyder when you click the “Run” button.

When I use the IPython console (which is available under Interpeters in Spyder!) I use several IPython specific things at the IPython prompt:

  • %run <filename>.py to run and interactively explore my script. This allows me to type plot(x); show() at the prompt and it finds the global variable x from <filename>.py
  • The output of Out[n] is accessible through _n (i.e., Out[7] available through _7).
  • function? to get help on “function” (which reads function’s docstring!)
  • !<shell> to run shell commands (cd and ls are also available separately)
  • %timeit <function> to time a function (by running it multiple times)
  • %cpaste <code> for copying/pasting code from the web
  • %matplotlib inline allows for inline graphics! Your plot doesn’t open up in a separate window; it’s just an output like anything else! (I show an example image below)

For more detail, look at IPython’s description of different magic functions.

Note: By default, Spyder doesn’t do the equivalent of clear all before running the script (but using %run <filename>.py does!). I recommend running the magic %reset at the prompt or running in a separate Python console.

Syntax

For questions on the Python/Matlab conversion (e.g., how do I index an array/matrix), I’ve found the NumPy for Matlab users sheet helpful. For basic syntax questions (e.g., what’s a for-loop look like?) I think this cheat sheet would be useful.

There’s a lot of syntax errors that are strange for beginners. For example, to concatenate two arrays, hstack((x, y)) is used. These double parentheses are difficult for a beginner to learn. To get around this, please please please look at NumPy for Matlab users or Google if you’re getting weird errors for something straightforward. If an error persists, I google something general and slowly refine the wording in my search.

pylab

from __future__ import division # if you're using Python 2 (don't)
from pylab import *

This will give you a Matlab-like environment as that’s pylab’s goal. However, from anything import * is not recommended. It imports a bunch of stuff into the global namespace. PEP 20, the Zen of Python says

Namespaces are one honking great idea – let’s do more of those!

Of course, I still use from pylab import * because it’s so darn convenient. I use it during development (not when publishing code) and you probably will too. EDIT I don’t use pylab anymore; because I know where each function lives (i.e., np.linalg.norm vs norm) pylab doesn’t provide much benefit.

Better practice would be explicitly define where each function is from, like below:

import numpy as np
import matplotlib.pyplot as plt
from scipy.io import loadmat, savemat # fyi
from numpy.random import rand, randn  # fyi (or uniform, gaussian_normal)

x = np.linspace(0, 1, num=100)
y = np.exp(-x) * np.cos(2 * np.pi * x)

plt.figure()
plt.plot(x, y, label='Moderate decay')
plt.legend(loc='best')
plt.show()

For more advanced Matlab stuff, I would be uncertain if Python had a certain feature/function. I learned that I could just google “python matlab function_name” and often get the result I wanted. “python matlab drawnow” gives python-drawnow and “python matlab cvx” gives cvxpy3 (a convex optimization library). I just run pip install cvxpy at the command line and I have the library!

Style

A complete style guide can be found at python-guide. This guide details Pythonic code and how to make your code easily readable and modular.

Python has many features that Matlab doesn’t. Language features like optional arguments and string formatting have been optimized for years in Python. These are incredibly nice features that Matlab doesn’t have.

These features are things that make the code Pythonic and easy to read/parse. This includes mixing function definitions and a script in the same file, optional arguments for functions, and some of the nice functions for for-loops (enumerate(), zip()).

Mixing function definitions and a script as well as optional arguments allows me to play with my script and see what effects certain parameters have. It becomes easy and natural to replace parameters with optional arguments, and then it becomes easy and natural to change those parameters.

I might wrap a function like this:

from pylab import *
import seaborn as sns

def f(t, tau=4, sigma=1/2):
    return cos(t*sigma) * exp(-t*tau)

t = linspace(0, 4, num=1e3)
taus = [1, 2, 3, 4, 5]
y = [f(t, tau=tau) for tau in taus]

figure()
for i, tau in enumerate(taus):
    plot(t, y[i], label=r'$\tau = {0}$'.format(tau))
legend(loc='best')
show()

Conclusion

At the end of the day, Python is what I develop signal processing algorithms in. I’ve found that it’s as fast as Matlab4 and has the numerical computation ease/syntax that Matlab has. But perhaps the nicest thing is that Python can handle any other task really well: default arguments, strings, functions, system commands, running a Python script from the shell and making interactive widgets are all easy.

  1. Try import antigravity 

  2. And Python syntax and semantics for more advanced concepts like list comprehension 

  3. cvxpy is actively developed by Steve Diamond, a member of Stephen Boyd’s group. It supports both Python 2 and Python 3. 

  4. There’s some interesting stuff with Julia, a language with Matlab-like syntax but C-like speeds.