0

I'm searching for a (probably obvious) way of reducing the time my code takes to run.

At the moment my code looks like this:

import numpy as np
from matplotlib import pyplot as plt

l = 4000000

def my_func(n):
    m = 3 * n
    z = n**2
    return(m,z)

am = []
az = []

for i in range(l): # question is referring to this loop
   am.append(my_func(i)[0])
   az.append(my_func(i)[1])

x = range(l)
plt.plot(x, am)
plt.plot(x, az)
plt.show()

In the i-loop my_func always runs twice and discards one of the two returned values, which sounds super inefficient to me. So how can I fill my am array with the first and my az array with the second values my_func returns, without running it twice for every i and only using half the returns every time?

2
  • Unpacking the results in advance seems sufficient. Commented May 2, 2022 at 13:58
  • How much of the time is spent on building the list and how much on plotting them? Commented May 2, 2022 at 16:57

8 Answers 8

3

You can unpack the tuple returned from this function:

for i in range(l):
    m, z = my_func(i)
    am.append(m)
    az.append(z)

This blog post nicely explains this concept in Python.

Sign up to request clarification or add additional context in comments.

Comments

2

The obvious solution is to assign a variable to the return value of your function.

result = my_func(i)
am.append(result[0])
az.append(result[1])

Better yet, just unpack the result.

m, z = my_func(i)
am.append(m)
az.append(z)

Comments

1

I would simply do without a separate function altogether and append the two arrays as

am.append(3*i)
az.append(i**2)

Comments

1

You can unpack the values:

m, z = my_func(i)
am.append(m)
az.append(z)

Comments

1
   am.append(my_func(i)[0])
   az.append(my_func(i)[1])

You can change to

   tup = my_func(i)
   am.append(tup[0])
   az.append(tup[1])

Then again, you don't need to call the function over here. You can easily do one thing.

x = np.arange(l)
plt.plot(x, 3*x)
plt.plot(x, x*x)
plt.show()

Timing

import numpy as np
from matplotlib import pyplot as plt
import time
start_time = time.time()

l = 4000000

def my_func(n):
    m = 3 * n
    z = n**2
    return(m,z)

am = []
az = []

for i in range(l): # question is referring to this loop
   am.append(my_func(i)[0])
   az.append(my_func(i)[1])

x = range(l)
plt.plot(x, am)
plt.plot(x, az)
plt.show()
print("--- %s seconds ---" % (time.time() - start_time))

Output:

enter image description here

Code-2

import numpy as np
from matplotlib import pyplot as plt
import time
start_time = time.time()

l = 4000000

# def my_func(n):
#     m = 3 * n
#     z = n**2
#     return(m,z)

# am = []
# az = []

# for i in range(l): # question is referring to this loop
#    am.append(my_func(i)[0])
#    az.append(my_func(i)[1])

x = np.arange(l)
plt.plot(x, 3*x)
plt.plot(x, x*x)
plt.show()
print("--- %s seconds ---" % (time.time() - start_time))

Output

enter image description here

Instead of using for loop, you can simply use vectorization to speed up the operation, as shown in the pictures( 5-6 times faster roughly). Also try to not call the same function multiple times to reuse the same value. Better to call it once and store the result.

3 Comments

@MechanicPig Ah yes. I was adding something else. Thanks for mentioning.
Thanks for your answer! Although you're right timing-wise my_func is just a dummy function I put in order to ask the question, the actual function does a lot more, but in the end just returns two values, hence the dummy function, which I can't eliminate completely as you did in the last version. Unpacking worked, as many before have suggested tho!
@Tim.: Most likely not possible to answer in this scope, but usually you can almost always avoid for loop. That is the message. Even if your function is doing a lot of thing, you can (almost) always vectorize it.
0

Just store the value in a variable :

results = my_func(i)
am.append(results[0])
az.append(results[1])

Comments

0

I would use np.vectorize

am, az = np.vectorize(my_func)(range(l))

Comments

0

Do you mean something like the below? Save the returned tuple and append to the lists.

import numpy as np
from matplotlib import pyplot as plt

l = 4000000

def my_func(n):
    m = 3 * n
    z = n**2
    return(m,z)

am = []
az = []

for i in range(l): # question is referring to this loop
    m, z = my_func(i)
    am.append(m)
    az.append(z)

x = range(l)
plt.plot(x, am)
plt.plot(x, az)
plt.show()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.