Implementation of linear regression in Python
Just reviewing normalizeFeatures.


Instead of a comment explaining what the function does, write a docstring. (Docstrings are available from the interactive interpreter via the help function.)
The function operates on the global variable X. This makes the function inflexible (you can't use it for anything other than modifying the particular variable X), and hard to test. It would be better if the function received the array as an argument, so that it could be used on any array:

def normalize_features(a):
    """Given array a with shape (m, n), update it so that each column
    (except column 0) has mean 0 and standard deviation 1. Return
    arrays mu, sigma with shape (1, n) where mu[0,i] is the original
    mean of a[:,i] and sigma[0,i] is the original standard deviation
    of a[:,i].

    """

This complicated specification can be simplified. First, we can avoid the "(except column 0)" bit and let the caller pass X[:,1:] if they want to leave column 0 alone. Second, we can return mu and sigma with shape (n,) instead of (1, n) and let the caller reshape if necessary (which it probably isn't).

def normalize_features(a):
    """Given array a with shape (m, n), update it so that each column has
    mean 0 and standard deviation 1. Return arrays mu, sigma giving
    the original mean and standard deviation of each column of a.

    """

The loop over the columns is unnecessary because numpy.mean and numpy.std take an axis argument. So the body of the function can be:

mu = a.mean(axis=0)
sigma = a.std(axis=0)
a[...] = (a - mu) / sigma
return mu, sigma

It might be better not to update the array X, but to compute a new array containing the normalized data (this uses twice the memory, but that's only a concern if X is really big). If you did this, then you wouldn't need to remember the original mean and standard deviation (because you still have the original data) and so the normalization becomes a one-liner:

def normalize_features(a):
    """Return copy of a with each column normalized so that it has mean 0
    and standard deviation 1.

    """
    return (a - a.mean(axis=0)) / a.std(axis=0)

Consider using scipy.stats.zscore instead of writing your own.