1

I guess the function parameter does not change the original variable. For e.g.

x=10

def mycal(someval):
    someval = someval * 2
    return someval

It will return 20 if I call the function:

mycal(x)
20

But the value of x is still 10:

x
10

Now why does the theta value has changed to 3.7 and 3.2 when I run this code?

import numpy as np

X = 2 * np.random.rand(100,1)
y = 4 +3 * X+np.random.randn(100,1)

def predict_func(slope,intercept,x_test):
    pred = ((np.dot(x_test, slope)) + intercept)        
    return pred

def mse_calc(prediction, y_test):
    error = np.mean((prediction - y_test)**2)
    return error

def grad_descent(s_theta, l_rate, tolerance, iter_val, x_train, y_train):

    n_data = len(x_train)
    bias = np.ones((n_data,1))
    s_intercept = s_theta[0]
    s_slope = s_theta[1:]
    prediction = predict_func(s_slope, s_intercept, x_train)
    error =  mse_calc(prediction, y_train)
    x_train_b = np.append(bias, x_train, axis = 1) 

    for i in range(iter_val):
        int_theta = [0 for i in range(len(x_train[0]) + 1)]
        n_pt = float(len(x_train))

        prediction = predict_func(s_slope, s_intercept, x_train)

        int_theta = 2 / n_pt * np.dot(x_train_b.T, (prediction - y_train))       
        s_theta -=  l_rate * int_theta

    s_intercept = s_theta[0]
    s_slope = s_theta[1:]
    prediction = predict_func(s_slope, s_intercept, x_train)
    final_error = mse_calc(prediction, y_train)

    return  s_theta, final_error


theta = np.zeros((len(X[0]) + 1, 1))
tolerance = 0.0001
l_rate = 0.01
iterations = 5000

print (theta)

grad_theta, grad_error  = grad_descent(theta, l_rate, tolerance, iterations, X, y)

print (theta)

I expect the theta value to be still 0 while grad_theta should be 3.7


In the following example, the first one is redefining the variable while the next 2 are pointers and appending mutable object.

some_list = some_list + [2]
some_list.append(2)
some_list += [2]

+= is close the option 2 and not option 1 as I expected.

What are += and -= any way?

shantanuo
  • 31,689
  • 78
  • 245
  • 403
  • Possible duplicate of [Why can a function modify some arguments as perceived by the caller, but not others?](https://stackoverflow.com/questions/575196/why-can-a-function-modify-some-arguments-as-perceived-by-the-caller-but-not-oth) – David Zemens Nov 19 '18 at 04:24

5 Answers5

2
someval = someval * 2

This redefines someval. After redefinition x and someval are no longer referring to the same object, so this doesn't modify x.

s_theta -=  l_rate * int_theta

This mutates s_theta, doesn't redefine it, so this will affect the value of theta too since s_theta and theta are still referring to the same object.

Julien
  • 13,986
  • 5
  • 29
  • 53
1

That is not completly true, in python some objects are mutable and some other are not. For example, strings and ints are inmutable, but list or dictionaries are mutable, check this example:

>>> x = []
>>> def add(l, v):
...     l.append(v)
... 
>>> add(x, 5)
>>> add(x, 5)
>>> x
[5, 5]

In your case, theta is a numpy array, hence it is mutable, that is why it changes.

Netwave
  • 40,134
  • 6
  • 50
  • 93
  • 1
    Well not quite... if you redefine a dict or a list, you'll have the same effect even if lists and dicts are mutable. The key point here is that redefining and mutating are fundamentally different things... – Julien Nov 19 '18 at 04:20
1

This is idea about mutable, the article of Mohan on Medium explicitly explain what is mutable in python.

List object, however, is mutable so you should consider it like pointer, which still pointing to same element.

Thus, you may have a function like

a = []
def change():
  a.append(1)
change()
print(a) #[1]

But

a = 0
def change():
  a += 1
change()
print(a) #0
MT-FreeHK
  • 2,462
  • 1
  • 13
  • 29
1

If you try this same procedure with a list, you'll see similar behavior with theta:

def myfunc(somelist):
    for i in range(len(somelist)):
        somelist[i] = 3

mylist = [0]*8
myfunc(mylist)
# mylist is now [3,3,3,3,3,3,3,3]

This is because in the function for your int, the python interpreter creates a new var local to the function, it isn't tracking a reference count to that int, because ints are immutable objects. However, lists are mutable, and so reference counting must be incorporated otherwise you can wind up with very unsafe behavior.

With this in mind, when you pass your list into a function, it is mutable and will be edited by the function that holds the reference to that variable. The int, however, is immutable, and therefore another copy is created as it goes through function scopes

C.Nivs
  • 12,353
  • 2
  • 19
  • 44
1

Numpy operates differently for = and -= operators. Check the following code snippet.

import numpy as np

def f(x):
  x = x - 1
  return x

def g(x):
  x -= 1
  return x

a = np.array([1,2])

b = f(a)
print (a, b)
>>> [1 2] [0 1]

c = g(a)
print (a, c)
>>> [0 1][0 1]
Quazi Marufur Rahman
  • 2,603
  • 5
  • 33
  • 51