Linear Regression on random data
Welcome!

Your first two lines are nice comments. Consider putting them in a module docstring:

"""Performs Linear Regression (from scratch) using randomized data.

Optimizes weights by using Gradient Descent Algorithm.
"""


Consider adding random noise to something linear (or to some "wrong model" sine or polynomial), rather than to a constant.

np.random.seed(0)


Nice - reproducibility is Good.

trainingSize = 10 ** 1
trainingSteps = 10 ** 3
learningRate = 10 ** -2


These expressions are correct and clear. But why evaluate a FP expression when you could just write it as a literal? 1e1, 1e3, 1e-2. (This answer would apply in many languages, including Python. And yes, I actually prefer seeing the two integers written as floating point, even if that forces me to call int() on them.)

PEP8 asks that you spell it training_size, and so on. Please run flake8, and follow its advice.

Your column names expression is fine. Consider handling the one-origin within the format expression:

col_names = [f'feature{i + 1}' for i in range(features)] + ['labels']


Specifying axis=1 is correct. I have a (weak) preference for explicitly spelling out: axis='columns'.

Consider hoisting the expression np.matmul(X, thetas) - y, so it is only evaluated once.

The three lambda expressions are fine, but they don't seem to buy you anything. Probably better to use def three times.

Ship it! But do consider noising a linear function, to make it easier to evaluate your results.