The other answers are right: copy() returns a shallow copy of the dictionary, so arr[map] will be a copy of test[map], but arr[map][mID] and arr[map][mID] will be exactly test[map][mID].
The following schema shows the situation:
arr  -+-> 'map1' -+-> { 'id1':{'val':0}, ... }
      |           |
      +-> 'map2' ---+-> { 'id1':{'val':2}, ... }
                  | |
test -+-> 'map1' -+ |
      |             |
      +-> 'map2' ---+
When you try to delete arr['map1']['id1'], you are also trying to delete test['map1']['id1'], yet you are iterating on test['map1']. That's why you are getting this error (the size of test['map1'] may not change while you are iterating on it).
But I don't think that a deepcopy is the good solution. All that you need is to copy the keys of arr[map] and iterate over this copy.
for map in arr:
    for mID in list(arr[map]): # here's the copy of the keys
        v = arr[map][mID]['val']
        if v < 1:
            del arr[map][mID] # allowed because you are not iterating on the dict, but on the copy of the keys
Try it online!
Some reading: How to avoid "RuntimeError: dictionary changed size during iteration" error?