python - How to randomly change positions of non-zero entries of an array where certain rows are excluded -


i have numpy array consisting of lot of 0s , few non-zero entries e.g. (just toy example):

myarray = np.array([[ 0.       ,  0.       ,  0.79],        [ 0.       ,  0.       ,  0.       ],        [ 0.       ,  0.       ,  0.       ],        [ 0.       ,  0.435    ,  0.       ]]) 

now move each of non-zero entries given probability means of entries moved, might remain @ current position. of rows not allowed contain non-zero entry means values not allowed moved there. implemented follows:

import numpy np  # reproducibility np.random.seed(2)  myarray = np.array([[ 0.       ,  0.       ,  0.79],        [ 0.       ,  0.       ,  0.       ],        [ 0.       ,  0.       ,  0.       ],        [ 0.       ,  0.435    ,  0.       ]])  # list of rows numbers not allowed moved    ignorerows = [2]  # moving probability probmove =  0.3  # non-zero entries nzentries = np.nonzero(myarray)   # indices of non-zero entries tuples indnz = zip(nzentries[0], nzentries[1])   # store values valnz = [myarray[i] in indnz]   # generating probabilities moving each non-zero entry lprob = np.random.rand(len(nzentries))   allowedrows = [ind ind in xrange(myarray.shape[0]) if ind not in ignorerows]  # replace "range" in python 3.x allowedcols = [ind ind in xrange(myarray.shape[1])]  # replace "range" in python 3.x  indprob, prob in enumerate(lprob):     # move probability     if prob <= probmove:         # randomly change position         myarray[np.random.choice(allowedrows), np.random.choice(allowedcols)] = valnz[indprob]          # set old position 0         myarray[indnz[indprob]] = 0.  print myarray    

first, determine indices , values of non-zero entries. assign probability each of these entries determines whether entry moved. allowed target rows.

in second step, loop through list of indices , move them according moving probability done choosing allowed rows , columns, assigning respective value these new indices , set "old" value 0.

it works fine code above, however, speed matters in case , wonder whether there more efficient way of doing this.

edit: hpaulj's answer helped me rid of for-loop nice , reason why accepted answer. incorporated comments , posted answer below well, in case else stumbles on example , wonders how used answer in end.

you can index elements arrays, so:

valnz=myarray[nzentries] 

can replace zip , comprehension.

simplify these 2 assignments:

allowedcols=np.arange(myarray.shape[1]); allowedrows=np.delete(np.arange(myarray.shape[0]), ignorerows) 

with:

i=lprob<probmove; valnz=valnz[i];indnz=indnz[i] 

you don't need perform prog<probmove test each time in loop; iterate on valnz , indnz.

i think random.choice can generated of these valnz @ once:

np.random.choice(np.arange(10), 10, true)   # 10 choices range replacement 

with should possible move of points without loop.

i haven't worked out details yet.

there 1 way in iterative move different parallel one. if destination choice value, iterative approach can on write, , possibly move given value couple of times. parallel code not perform sequential moves. have decide whether 1 correct or not.

there ufunc method, .at, performs unbuffered operations. works operations add, don't know if apply indexing move this.


simplified version of iterative moving:

in [106]: arr=np.arange(20).reshape(4,5) in [107]: i=np.nonzero(arr>10) in [108]: v=arr[i] in [109]: rows,cols=np.arange(4),np.arange(5)  in [110]: in range(len(v)):     dest=(np.random.choice(rows),np.random.choice(cols))     arr[dest]=v[i]     arr[i[0][i],i[1][i]] = 0  in [111]: arr out[111]:  array([[ 0, 18,  2, 14, 11],        [ 5, 16,  7, 13, 19],        [10,  0,  0,  0,  0],        [ 0, 17,  0,  0,  0]]) 

possible vectorized version:

in [117]: dest=(np.random.choice(rows,len(v),true),np.random.choice(cols,len(v),true))  in [118]: dest out[118]: (array([1, 1, 3, 1, 3, 2, 3, 0, 0]), array([3, 0, 0, 1, 2, 3, 4, 0, 1]))  in [119]: arr[dest] out[119]: array([ 8,  5, 15,  6, 17, 13, 19,  0,  1]) in [120]: arr[i]=0 in [121]: arr[dest]=v  in [122]: arr out[122]:  array([[18, 19,  2,  3,  4],        [12, 14,  7, 11,  9],        [10,  0,  0, 16,  0],        [13,  0, 15,  0, 17]]) 

if sets 0 after, there more zeros.

in [124]: arr[dest]=v     in [125]: arr[i]=0 in [126]: arr out[126]:  array([[18, 19,  2,  3,  4],        [12, 14,  7, 11,  9],        [10,  0,  0,  0,  0],        [ 0,  0,  0,  0,  0]]) 

same dest, done iteratively:

in [129]: in range(len(v)):    .....:     arr[dest[0][i],dest[1][i]] = v[i]    .....:     arr[i[0][i],i[1][i]] = 0  in [130]: arr out[130]:  array([[18, 19,  2,  3,  4],        [12, 14,  7, 11,  9],        [10,  0,  0, 16,  0],        [ 0,  0,  0,  0,  0]]) 

with small size, , high moving density, differences between iterative , vectorized solutions large. sparse array fewer.


Comments

Popular posts from this blog

angularjs - ADAL JS Angular- WebAPI add a new role claim to the token -

php - CakePHP HttpSockets send array of paramms -

node.js - Using Node without global install -