pierresegonne
pierresegonne

Reputation: 446

Improvement on copy array elements numpy

I have a question regarding variable assignation and memory allocation in a simple case.

Imagine that I am initialising a state vector x, with initial value x0. I am then making iterative updates on that state vector with buffer array X and after each iteration, I store the new state vector in a storage list L. An outline of my initial implementation can be found in the following snippet:

import numpy as np

np.random.seed(11)

x0 = 1
L = [x0]
x = x0

X = np.zeros((3,1))

for i in range(10):
    X[-1, :] = np.random.normal() # To simulate operations on X
    x = X[-1, :]
    L.append(x)

print(L)

Which would print that L holds

[1 array([-1.06560298]) array([-1.06560298]) array([-1.06560298])
 array([-1.06560298]) array([-1.06560298]) array([-1.06560298])
 array([-1.06560298]) array([-1.06560298]) array([-1.06560298])
 array([-1.06560298])]

Because when x is appended to L, only the reference to X[-1, :] is added, not the actual value.

The solution I could find is to use np.copy to copy the values of the last row of X into x and then append it, as can be seen in the following snippet.

import numpy as np

np.random.seed(11)

x0 = 1
L = [x0]
x = x0

X = np.zeros((3,1))

for i in range(10):
    X[-1, :] = np.random.normal() # To simulate operations on X
    x = np.copy(X[-1, :])
    L.append(x)

print(L)

The output shows that indeed the modifications on the state x are correctly recorded.

[1 array([1.74945474]) array([-0.286073]) array([-0.48456513])
 array([-2.65331856]) array([-0.00828463]) array([-0.31963136])
 array([-0.53662936]) array([0.31540267]) array([0.42105072])
 array([-1.06560298])]

I wonder if there would be a more elegant or efficient way to solve this problem?

Thanks!

Upvotes: 1

Views: 60

Answers (2)

Mad Physicist
Mad Physicist

Reputation: 114588

Don't mix numpy arrays and python lists if you can avoid it. If you know the number of iterations, pre-allocate a buffer to hold the whole thing (e.g., with np.empty):

import numpy as np

np.random.seed(11)

N = 10

L = np.empty(N)
L[0] = 1

X = np.zeros(3)

for i in range(N):
    L[i] = X[-1] = np.random.normal()

print(L)

On the other hand, if all you need is to get the scalar from a 1-element array, you can use the item method:

x = X[:, -1].item()

Upvotes: 1

mapf
mapf

Reputation: 2088

I am not entirely sure I understand what you want to do, but maybe numpy.append() is what you are looking for:

import numpy as np

np.random.seed(11)

x = np.array([1.])

for i in range(10):
    x = np.append(x, np.random.normal())

print(x)

Upvotes: 1

Related Questions