Обновление вложенного словаря в defaultdict

При попытке обновить мой словарь под вложенным collection.defaultdict Python выдал мне ошибку

Говоря

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "program.py", line 18, in train_ngrams
    if graphemes[i] not in mydict[phonemes[i]].keys():
AttributeError: 'str' object has no attribute 'keys'

Мой код:

import csv
from collections import defaultdict

def train_ngrams(train_file):
    mydict = defaultdict(dict)
    phonemes = []
    graphemes = []
    with open(train_file, 'r') as f:
        reader = csv.reader(f) 
        next(reader)
        for p, g in reader:
            phonemes += p.split()
            graphemes += g.split()
            for i in range(len(phonemes)):
                if phonemes[i] not in mydict.keys():
                    mydict.update({phonemes[i] : graphemes[i]})
                    if graphemes[i] not in mydict[phonemes[i]].keys():
                        mydict[phonemes[i]].update({phonemes[i] : (graphemes.count(graphemes[i]) for graphemes[i] in graphemes) - 1})
                    else:
                        mydict[phonemes[i]][graphemes[i]] += 1         

Дело в том, что я пытаюсь обновить словарь, когда перебираю CSV-файл. И здесь я сначала хочу проверить, есть ли он уже в defaultdict. Если нет, то я хочу создать пару ключ-значение.

И значение здесь в defaultdict на самом деле будет использоваться позже для реализации вложенного словаря нормалей, в котором хранятся некоторые данные о частоте.

Вот пример:

defaultdict(<class 'dict'>, {'T': {'t': 2}, 'UH': {'oo': 1}})

Каков краткий способ обработки этой ошибки? Обратите внимание, что defaultdict необходим в этой части.

РЕДАКТИРОВАТЬ:

train_ngrams("training-data-ex1.csv")

Желаемый результат должен быть

defaultdict(<class 'dict'>, {'T': {'t': 2}, 'UH': {'oo': 1}})

РЕДАКТИРОВАТЬ:

Образец текстового файла

phonemes,graphemes
T UH T,t oo t

person 2Xchampion    schedule 02.05.2016    source источник
comment
mydict[phonemes[i]] возвращает значение ключа   -  person styvane    schedule 02.05.2016
comment
Что ты пытаешься сделать? В строках mydict.update({phonemes[i] : graphemes[i]}); if graphemes[i] not in mydict[phonemes[i]].keys(): вы в основном проверяете if graphemes[i] not in graphemes[i].keys():, что не имеет особого смысла.   -  person tobias_k    schedule 02.05.2016
comment
@tobias_k Я хочу проверить, существует ли эта пара ключ-значение в defaultdict, если нет, то мне придется обновить его с помощью этого значения и пары, чтобы я мог фактически манипулировать им и получить нужный результат.   -  person 2Xchampion    schedule 02.05.2016
comment
@tobias_k добавил. Прости за это.   -  person 2Xchampion    schedule 02.05.2016
comment
@user3100115 user3100115 Но мне нужно, чтобы это значение ключа было позже вложенным словарем, как вы можете видеть в строках ниже, что я хотел обновить значение, чтобы оно стало другим словарем.   -  person 2Xchampion    schedule 02.05.2016
comment
Почему oo не добавляется к T? Должны ли они быть в паре? Всегда ли фонем столько же, сколько и графем?   -  person tobias_k    schedule 02.05.2016
comment
@tobias_k Да, всегда одинаковое количество фонем и графем. Также «oo» соединен с «UH» из-за его положения (значение oo находится в графемах [1] так же, как «UH» в фонемах [1]).   -  person 2Xchampion    schedule 02.05.2016


Ответы (1)


Если вы хотите соединить элементы в пары, вам нужно использовать zip, а не двойной цикл.

mydict = collections.defaultdict(lambda: collections.defaultdict(int))
with open("training-data-ex1.csv") as f:
    reader = csv.reader(f)
    next(reader) # skip header
    for phonemes, graphemes in reader:
        for p, g in zip(phonemes.split(), graphemes.split()):
            mydict[p][g] += 1

Здесь используется defaultdict из defaultdict из int, поэтому результат выглядит немного странно, но, по сути, именно то, что вы хотели: defaultdict(<function <lambda> at 0x7fd297740840>, {'T': defaultdict(<class 'int'>, {'t': 2}), 'UH': defaultdict(<class 'int'>, {'oo': 1})}) или, без всего этого шаблонного defaultdict, {'T': {'t': 2}, 'UH': {'oo': 1}}.

person tobias_k    schedule 02.05.2016
comment
Будет ли zip сначала удалять дубликаты в контейнере, а затем преобразовывать его в диктофон? - person 2Xchampion; 02.05.2016
comment
Нет, zip просто перебирает пары. Вместо того, чтобы удалять дубликаты и затем использовать счетчик, просто перебирайте пары и подсчитывайте +1 для каждого. Гораздо проще. - person tobias_k; 02.05.2016
comment
Я вижу, я обязательно попробую это и посмотрю, как это пойдет. Благодарю вас! - person 2Xchampion; 02.05.2016