List of pandas arrays assigning rows

Viewed 32

I have a list composed of 5 pandas arrays, size 4 by 3 each. I want to change the 3rd row of them to a row of 0s, of ones, of twos, whatever is the index of the array in the list. I write the code, a for-loop, and it looks like it is working as I am printing the results:

A=pd.DataFrame(np.random.randn(4,3))
AList=5*[A]
AList[0].iloc[2,:]
for kkk0 in range(0,len(AList)):
    AList[kkk0].iloc[2,:]=kkk0*np.ones((1,3))
    print(AList[kkk0])
          0         1         2
0 -0.168639  0.300507  2.823529
1  0.608844  0.017578 -0.342164
2  0.000000  0.000000  0.000000
3  1.664176 -0.696303  0.239165
          0         1         2
0 -0.168639  0.300507  2.823529
1  0.608844  0.017578 -0.342164
2  1.000000  1.000000  1.000000
3  1.664176 -0.696303  0.239165
          0         1         2
0 -0.168639  0.300507  2.823529
1  0.608844  0.017578 -0.342164
2  2.000000  2.000000  2.000000
3  1.664176 -0.696303  0.239165
          0         1         2
0 -0.168639  0.300507  2.823529
1  0.608844  0.017578 -0.342164
2  3.000000  3.000000  3.000000
3  1.664176 -0.696303  0.239165
          0         1         2
0 -0.168639  0.300507  2.823529
1  0.608844  0.017578 -0.342164
2  4.000000  4.000000  4.000000
3  1.664176 -0.696303  0.239165

The absurdity begins now however: When I try to see the contents of the AList after the ending of the for-loop I have that all the constituent PAndas arrays of the List have their third row as a row of 4s!

AList
Out[3]: 
[          0         1         2
 0 -0.168639  0.300507  2.823529
 1  0.608844  0.017578 -0.342164
 2  4.000000  4.000000  4.000000
 3  1.664176 -0.696303  0.239165,
           0         1         2
 0 -0.168639  0.300507  2.823529
 1  0.608844  0.017578 -0.342164
 2  4.000000  4.000000  4.000000
 3  1.664176 -0.696303  0.239165,
           0         1         2
 0 -0.168639  0.300507  2.823529
 1  0.608844  0.017578 -0.342164
 2  4.000000  4.000000  4.000000
 3  1.664176 -0.696303  0.239165,
           0         1         2
 0 -0.168639  0.300507  2.823529
 1  0.608844  0.017578 -0.342164
 2  4.000000  4.000000  4.000000
 3  1.664176 -0.696303  0.239165,
           0         1         2
 0 -0.168639  0.300507  2.823529
 1  0.608844  0.017578 -0.342164
 2  4.000000  4.000000  4.000000
 3  1.664176 -0.696303  0.239165]

Any ideas?

2 Answers
A=pd.DataFrame(np.random.randn(4,3))
AList=5*[A]

# concat your list of frames
df = pd.concat(AList)
# use loc to assign values 
# use numpy's transpose with arange since you know the size of each padnas frame
df.loc[2, :] = np.transpose([np.arange(0,5)]*3)
# use numpy's split to split you frame back into a list of frames
AList_new = np.split(df, len(AList))

[          0         1         2
 0  1.687788 -0.770912 -0.027720
 1 -1.868220 -0.475117 -0.266580
 2  0.000000  0.000000  0.000000
 3 -0.537249  0.414133  1.623596,
           0         1         2
 0  1.687788 -0.770912 -0.027720
 1 -1.868220 -0.475117 -0.266580
 2  1.000000  1.000000  1.000000
 3 -0.537249  0.414133  1.623596,
           0         1         2
 0  1.687788 -0.770912 -0.027720
 1 -1.868220 -0.475117 -0.266580
 2  2.000000  2.000000  2.000000
 3 -0.537249  0.414133  1.623596,
           0         1         2
 0  1.687788 -0.770912 -0.027720
 1 -1.868220 -0.475117 -0.266580
 2  3.000000  3.000000  3.000000
 3 -0.537249  0.414133  1.623596,
           0         1         2
 0  1.687788 -0.770912 -0.027720
 1 -1.868220 -0.475117 -0.266580
 2  4.000000  4.000000  4.000000
 3 -0.537249  0.414133  1.623596]

it's not an absurdity at all. The reason for the observed behavior is, that you create a list with 5 times the same object. Although you use a different index to access AList you always access the same object and so if you print it at last, the object will have the last value in row 2, which is 4. If you perform the logic of @It_is_Chris, the 5 objects get concatenated and then split again. That is a longish way to produce copies, you could also do it like this with a minimal change of your code:

import numpy as np

A=pd.DataFrame(np.random.randn(4,3))
# instead of creating a list with 5 identical 
# objects using 5 * [A], create 5 copies 
AList=[A.copy() for _ in range(5)]
AList[0].iloc[2,:]
for kkk0 in range(0,len(AList)):
    AList[kkk0].iloc[2,:]=kkk0*np.ones((1,3))
    print(AList[kkk0])
    
AList    

Output:

[          0         1         2
 0  0.319473 -0.503133 -0.394476
 1 -1.032836 -1.212072 -0.771076
 2  0.000000  0.000000  0.000000
 3  0.173137  0.387402 -1.256148,
           0         1         2
 0  0.319473 -0.503133 -0.394476
 1 -1.032836 -1.212072 -0.771076
 2  1.000000  1.000000  1.000000
 3  0.173137  0.387402 -1.256148,
           0         1         2
 0  0.319473 -0.503133 -0.394476
 1 -1.032836 -1.212072 -0.771076
 2  2.000000  2.000000  2.000000
 3  0.173137  0.387402 -1.256148,
           0         1         2
 0  0.319473 -0.503133 -0.394476
 1 -1.032836 -1.212072 -0.771076
 2  3.000000  3.000000  3.000000
 3  0.173137  0.387402 -1.256148,
           0         1         2
 0  0.319473 -0.503133 -0.394476
 1 -1.032836 -1.212072 -0.771076
 2  4.000000  4.000000  4.000000
 3  0.173137  0.387402 -1.256148]
Related