DavidC.
DavidC.

Reputation: 677

Nested loops over 2D and 1D numpy arrays saving into files

Statement of the problem:

Given three 1D numpy arrays and three 2D numpy arrays:

1D numpy arrays:
V = [ V_a V_b]
EL = [EL_a EL_b]
E0 = [E0_a E0_b]

2D numpy arrays:
T =  [[ T_1a  T_2a  T_3a  T_4a ] [ T_1b  T_2b  T_3b  T_4b ]]
ET = [[ ET_1a ET_2a ET_3a ET_4a] [ ET_1b ET_2b ET_3b ET_4b]]
TS = [[ TS_1a TS_2a TS_3a TS_4a] [ TS_1b TS_2b TS_3b TS_4b]]

I would like to create four files:

T_1.dat
T_2.dat
T_3.dat
T_4.dat

with the following info:

T_1.dat                           |    T_2.dat                     |    T_3.dat                      |    T_4.dat
----------------------------------------------------------------------------------------------------------------------------------------
VOLUME:           F:              | VOLUME:           F:           | VOLUME:           F:            | VOLUME:           F:
                                  |                                |                                 |
V_a              F(V_a, T_1)      | V_a              F(V_a, T_2)   | V_a              F(V_a, T_3)    | V_a              F(V_a, T_4)
V_b              F(V_b, T_1)      | V_b              F(V_b, T_2)   | V_b              F(V_b, T_3)    | V_b              F(V_b, T_4)

where F is calculated as:

F(V_a, T_1) = EL_a + E0_a + ET_1a - TS_1a
F(V_b, T_1) = EL_b + E0_b + ET_1b - TS_1b

... and so on ...

My attempt:

The following nested loops over all these variables:

import numpy as np

V =  np.array([ 226.331804,  228.817957])
EL = np.array([-3765.00423366, -3765.0072724 ])
E0 = np.array([ 0.07389338,  0.07347015])

T =  np.array([[ 10.,   30.1,  50.2,  70.3],
 [ 10.,   30.1,  50.2,  70.3]])

ET =  np.array([[  2.86370000e-08,   3.59345110e-05,   2.47740762e-04,   7.11121913e-04],
 [  4.16950000e-08,   4.07323670e-05,   2.66315355e-04,   7.47534260e-04]])

TS =  np.array([[  3.14910000e-08,   4.50715970e-05,   3.33253672e-04,   1.00376212e-03],
 [  4.60170000e-08,   5.14553150e-05,   3.61155871e-04,   1.06376830e-03]])

rows = ET.shape[0]
cols = ET.shape[1]

F_all = []
for x, indx_EL, indx_E0 in zip(range(0, rows), range(len(EL)), range(len(E0))):
    aux = []
    for y in range(0, cols):
        F = EL[indx_EL] + E0[indx_E0] + ET[x,y] + TS[x,y]
        print F
        aux.append(F)
    F_all.append(aux)    
F_all = np.array(F_all)
print ' F_all = ', F_all

The result is the following:

 F_all =  [[-3764.93034022 -3764.93025927 -3764.92975929 -3764.9286254 ]
 [-3764.93380216 -3764.93371006 -3764.93317478 -3764.93199095]]

If I manually calculate the first element I see it does not coincide with the calculated one.

F(V_a, T_1) = EL_a + E0_a + ET_1a - TS_1a
            = -3765.00423366 + 0.07389338 + 2.86370000e-08 - 3.14910000e-08 
            = -3764.93034028285

I cannot see the reason why is the nested loop failing? In addition, is this the best way to generate the above T_i.dat files ?

Upvotes: 0

Views: 516

Answers (2)

DavidC.
DavidC.

Reputation: 677

Thanks to @Piinthesky answer, it should be -TS[x, y] in the inner loop:

F_all = []
for x, indx_EL, indx_E0 in zip(range(0, rows), range(len(EL)), range(len(E0))):
    aux = []
    for y in range(0, cols):
        F = EL[indx_EL] + E0[indx_E0] + ET[x,y] - TS[x,y]
        aux.append(F)
    F_all.append(aux)

F_all = np.array(F_all)
print ' F_all looping = ', F_all

which yields:

F_all looping = [[-3764.93034028 -3764.93034941 -3764.93042579 -3764.93063291] [-3764.93380225 -3764.93381297 -3764.93389709 -3764.93411848]]

It is very interesting the broadcasting approach:

print 'EL + E0 = ', EL + E0
print 'np.shape(EL + E0) = ', np.shape(EL + E0)

EL + E0 = [-3764.93034027 -3764.93380225]

np.shape(EL + E0) = (2,)

print 'ET - TS = ', ET - TS
print 'np.shape(ET - TS) = ', np.shape(ET - TS)

ET - TS = [[ -2.85400000e-09 -9.13708600e-06 -8.55129100e-05 -2.92640207e-04] [ -4.32200000e-09 -1.07229480e-05 -9.48405160e-05 -3.16234040e-04]]

np.shape(ET - TS) = (2, 4)

In order to perform (EL + E0) + (ET - TS) through broadcasting, since (ET - TS) is of shape (2, 4) and (EL + E0) of shape (2,), we would have to transform (EL + E0) to be of shape (2, 1). Currently it is shape (2,). In order to create an axis with length 1, @Piinthesky 's None approach is very suitable:

print '(EL + E0)[:, None] = ', (EL + E0)[:, None]
print 'np.shape((EL + E0)[:, None]) = ', np.shape((EL + E0)[:, None])

(EL + E0)[:, None] = [[-3764.93034027] [-3764.93380225]]

np.shape((EL + E0)[:, None]) = (2, 1)

So, now, we can broadcast:

F_all = (EL + E0)[:, None] + (ET - TS)
print ' F_all broadcasting = ', F_all

F_all broadcasting = [[-3764.93034028 -3764.93034941 -3764.93042579 -3764.93063291] [-3764.93380225 -3764.93381297 -3764.93389709 -3764.93411848]]

which yields the same result as my F_all_looping approach.

Upvotes: 0

Mr. T
Mr. T

Reputation: 12410

You are making your life harder than necessary by looping over the index. I heard quite often here on SO "If you use numpy with loops you are probably doing it wrong". And it is true. You can instead use numpy broadcasting:

F_all = (EL + E0)[:, None] + (ET - TS)

Et voila.

P.S.: I am not going to do your debugging, but shouldn't it be -TS[x, y] in your inner loop?

Upvotes: 1

Related Questions