Reputation: 109
I want to create a dictionary to record the accurancy when I run the program.There are some problem when I give the values to the certain key
Here, I create a dictionary to record the accurancy when it trains or validate
acc = dict.fromkeys(['train', 'val'], dict.fromkeys(['pa', 'iou', 'dice'], 0))
The original dictionary looks like this
{'train': {'pa': 0, 'iou': 0, 'dice': 0}, 'val': {'pa': 0, 'iou': 0, 'dice': 0}}
Now, I give the some values for testing
acc['train']['pa'] = 0.9
acc['train']['iou'] = 0.8
acc['train']['dice'] = 0.7
The problems is all the values in key val
becomes the same
{'train': {'pa': 0.9, 'iou': 0.8, 'dice': 0.7}, 'val': {'pa': 0.9, 'iou': 0.8, 'dice': 0.7}}
Upvotes: 1
Views: 84
Reputation: 604
If the provided value is a mutable object (whose value can be modified) like list, dictionary, etc., when the mutable object is modified, each element of the sequence also gets updated. This is because, each element is assigned a reference to the same object (points to the same object in the memory).
In your problem, dict.fromkeys(['pa', 'iou', 'dice'], 0)
returns a dictionary which is mutable type, so each element is assigned to the same object.
To avoid this issue, you can use dictionary comprehension.
from copy import copy
# keys
keys = ['train', 'val']
value = dict.fromkeys(['pa', 'iou', 'dice'], 0 )
acc = { key : copy(value) for key in keys }
print(acc)
# updating the value
acc['train']['pa'] = 2
print(acc)
Source: https://www.programiz.com/python-programming/methods/dictionary/fromkeys
Upvotes: 1
Reputation: 78690
That's because dict.fromkeys(['pa', 'iou', 'dice'], 0)
is called exactly once, not once for each key in acc
.
>>> acc['train'] is acc['val']
True
The dictionaries are the same object in memory, you just have two ways to access it - via acc['train']
and acc['val']
.
You could use a defaultdict
with a function that creates a new dictionary on demand:
>>> from collections import defaultdict
>>> d = defaultdict(lambda: {'pa': 0, 'iou': 0, 'dice': 0})
>>> d['train']
{'pa': 0, 'iou': 0, 'dice': 0}
>>> d['val']
{'pa': 0, 'iou': 0, 'dice': 0}
>>> d['train']['pa'] = 1
>>> d['train']
{'pa': 1, 'iou': 0, 'dice': 0}
>>> d['val']
{'pa': 0, 'iou': 0, 'dice': 0}
However, be aware that this creates a new dictionary each time you access a new key:
>>> d['foo']
{'pa': 0, 'iou': 0, 'dice': 0}
If you don't want that, create a dictionary for each key manually with a dict comprehension:
>>> keys = ['train', 'val']
>>> d = {k:{'pa': 0, 'iou': 0, 'dice': 0} for k in keys}
>>> d['train']['pa'] = 1
>>> d['train']
{'pa': 1, 'iou': 0, 'dice': 0}
>>> d['val']
{'pa': 0, 'iou': 0, 'dice': 0}
Upvotes: 1