I try to make a table where I calculate an expectation value and vary 3 different parameters i,j,k (and also average over 20 values each). The expected result is a (4,6,5) table/list structure that has 120 different entries depending on the parameters indexed by i,j,k. The final step where I average the values does not work. The actual result is that there are only 5 different entries that appear 24 times each. I recreated a similar simplified problem where the averaging is not necessary as the values for a certain (i,j,k) do not differ, but where zt is the input list with different entries (i times j times k), and z is the output list that should show all possible combinations of (i times j times k), but it does not. It appears that only the last (i,j) is taken for each k. The problem is obviously in the loop, but I have no clue why it does not work as it should. Below is the code and the result z.
import numpy as np
zt = np.zeros([4,6,5,20])
z = [[['']*5]*6]*4
for i in range(4):
for j in range(6):
for k in range(5):
for l in range(20):
zt[i][j][k][l] = i*j*k
E0mean = np.sum(zt[i][j][k])/20 #Mean of the n calculations
E0dev = max(zt[i][j][k])-min(zt[i][j][k])/2 #uncertaincy
z[i][j][k] = str(round(E0mean,5)) u"\u00B1" str(round(E0dev,5)) #results: mean - uncertainty
z
Output:
[[['0.0±0.0', '15.0±0.0', '30.0±0.0', '45.0±0.0', '60.0±0.0'],
['0.0±0.0', '15.0±0.0', '30.0±0.0', '45.0±0.0', '60.0±0.0'],
['0.0±0.0', '15.0±0.0', '30.0±0.0', '45.0±0.0', '60.0±0.0'],
['0.0±0.0', '15.0±0.0', '30.0±0.0', '45.0±0.0', '60.0±0.0'],
['0.0±0.0', '15.0±0.0', '30.0±0.0', '45.0±0.0', '60.0±0.0'],
['0.0±0.0', '15.0±0.0', '30.0±0.0', '45.0±0.0', '60.0±0.0']],
[['0.0±0.0', '15.0±0.0', '30.0±0.0', '45.0±0.0', '60.0±0.0'],
['0.0±0.0', '15.0±0.0', '30.0±0.0', '45.0±0.0', '60.0±0.0'],
['0.0±0.0', '15.0±0.0', '30.0±0.0', '45.0±0.0', '60.0±0.0'],
['0.0±0.0', '15.0±0.0', '30.0±0.0', '45.0±0.0', '60.0±0.0'],
['0.0±0.0', '15.0±0.0', '30.0±0.0', '45.0±0.0', '60.0±0.0'],
['0.0±0.0', '15.0±0.0', '30.0±0.0', '45.0±0.0', '60.0±0.0']],
[['0.0±0.0', '15.0±0.0', '30.0±0.0', '45.0±0.0', '60.0±0.0'],
['0.0±0.0', '15.0±0.0', '30.0±0.0', '45.0±0.0', '60.0±0.0'],
['0.0±0.0', '15.0±0.0', '30.0±0.0', '45.0±0.0', '60.0±0.0'],
['0.0±0.0', '15.0±0.0', '30.0±0.0', '45.0±0.0', '60.0±0.0'],
['0.0±0.0', '15.0±0.0', '30.0±0.0', '45.0±0.0', '60.0±0.0'],
['0.0±0.0', '15.0±0.0', '30.0±0.0', '45.0±0.0', '60.0±0.0']],
[['0.0±0.0', '15.0±0.0', '30.0±0.0', '45.0±0.0', '60.0±0.0'],
['0.0±0.0', '15.0±0.0', '30.0±0.0', '45.0±0.0', '60.0±0.0'],
['0.0±0.0', '15.0±0.0', '30.0±0.0', '45.0±0.0', '60.0±0.0'],
['0.0±0.0', '15.0±0.0', '30.0±0.0', '45.0±0.0', '60.0±0.0'],
['0.0±0.0', '15.0±0.0', '30.0±0.0', '45.0±0.0', '60.0±0.0'],
['0.0±0.0', '15.0±0.0', '30.0±0.0', '45.0±0.0', '60.0±0.0']]]
CodePudding user response:
When using [xxx]*3
, I make a list of 3 items, all referencing the same object. That list multiplication does not make copies. This is a python 101 gotcha.
In [178]: alist =[['xxx']]*3
In [179]: alist
Out[179]: [['xxx'], ['xxx'], ['xxx']]
In [180]: alist[0]
Out[180]: ['xxx']
Changing one reference changes them all:
In [181]: alist[0][0]='yyy'
In [182]: alist
Out[182]: [['yyy'], ['yyy'], ['yyy']]
Sometimes the *
replication works, but you have to be careful. It's better to use a list comprehension like this:
In [183]: alist = [['xxx'] for _ in range(3)]
In [184]: alist
Out[184]: [['xxx'], ['xxx'], ['xxx']]
In [185]: alist[0][0]='yyy'
In [186]: alist
Out[186]: [['yyy'], ['xxx'], ['xxx']]
Each ['xxx']
is a new list, not a duplicate reference.
A numpy
requivalent is:
In [188]: arr = np.full((3,1),'xxx')
In [189]: arr
Out[189]:
array([['xxx'],
['xxx'],
['xxx']], dtype='<U3')
In [191]: arr[0,0]='yyy'
In [192]: arr
Out[192]:
array([['yyy'],
['xxx'],
['xxx']], dtype='<U3')
Often when building a list of lists it's easier to use append
:
In [193]: alist = []
...: for i in range(3):
...: blist = []
...: for j in range(4):
...: blist.append(f'<{i},{j}>')
...: alist.append(blist)
...:
In [194]: alist
Out[194]:
[['<0,0>', '<0,1>', '<0,2>', '<0,3>'],
['<1,0>', '<1,1>', '<1,2>', '<1,3>'],
['<2,0>', '<2,1>', '<2,2>', '<2,3>']]
The list comprehension equilvalent:
In [196]: [[f'<{i},{j}>' for j in range(4)] for i in range(3)]
Out[196]:
[['<0,0>', '<0,1>', '<0,2>', '<0,3>'],
['<1,0>', '<1,1>', '<1,2>', '<1,3>'],
['<2,0>', '<2,1>', '<2,2>', '<2,3>']]
CodePudding user response:
I think this does what you want:
import numpy as np
zt = np.zeros([4,6,5,20])
z = []
for i in range(4):
z2 = []
for j in range(6):
z3 = []
for k in range(5):
for l in range(20):
zt[i][j][k][l] = i*j*k
E0mean = np.sum(zt[i][j][k])/20 #Mean of the n calculations
E0dev = max(zt[i][j][k])-min(zt[i][j][k])/2 #uncertaincy
z3.append( str(round(E0mean,5)) u"\u00B1" str(round(E0dev,5)) ) #results: mean - uncertainty
z2.append(z3)
z.append(z2)