Организация данных XML в словари - PullRequest
0 голосов
/ 21 июля 2011

Я пытаюсь организовать свои данные в формате словаря из данных XML.Это будет использоваться для запуска симуляции Монте-Карло.

Вот пример того, как выглядит пара записей в XML:

<retirement>
    <item>
        <low>-0.34</low>
        <high>-0.32</high>
        <freq>0.0294117647058824</freq>
        <variable>stock</variable>
        <type>historic</type>
    </item>
    <item>
        <low>-0.32</low>
        <high>-0.29</high>
        <freq>0</freq>
        <variable>stock</variable>
        <type>historic</type>
    </item>
</retirement>

Мои текущие наборы данных имеют только две переменные итип может быть 1 из 3 или, возможно, 4 дискретных типа.Жесткое кодирование двух переменных не является проблемой, но я хотел бы начать работать с данными, которые имеют гораздо больше переменных, и автоматизировать этот процесс.Моя цель состоит в том, чтобы автоматически импортировать эти данные XML в словарь, чтобы иметь возможность впоследствии манипулировать ими без необходимости жесткого кода в заголовках массива и переменных.

Вот что у меня есть:

# Import XML Parser
import xml.etree.ElementTree as ET

# Parse XML directly from the file path
tree = ET.parse('xmlfile')

# Create iterable item list
Items = tree.findall('item')

# Create Master Dictionary
masterDictionary = {}

# Assign variables to dictionary
for Item in Items:
    thisKey = Item.find('variable').text
    if thisKey in masterDictionary == False:
        masterDictionary[thisKey] = []
    else:
        pass

thisList = masterDictionary[thisKey]
newDataPoint = DataPoint(float(Item.find('low').text), float(Item.find('high').text), float(Item.find('freq').text))
thisSublist.append(newDataPoint)

Я получаю KeyError @ thisList = masterDictionary [thisKey]

Я также пытаюсь создать класс для работы с некоторыми другими элементами xml:

# Define a class for each data point that contains low, hi and freq attributes
class DataPoint:
 def __init__(self, low, high, freq):
  self.low = low
  self.high = high
  self.freq = freq

Могу ли я тогда проверить значение с чем-то вроде:

masterDictionary['stock'] [0].freq

Любая и вся помощь приветствуется

ОБНОВЛЕНИЕ

Спасибоза помощь Джон.Проблемы с отступами - неряшливость с моей стороны.Это моя первая публикация в стеке, и я просто не понял, как правильно копировать / вставить.Часть после else: фактически имеет отступ для цикла for, а класс содержит четыре пробела в моем коде - просто плохая публикация здесь.Я буду помнить соглашение о капитализации.Ваше предложение действительно сработало, и теперь с командами:

print masterDictionary.keys()
print masterDictionary['stock'][0].low

выход:

['inflation', 'stock']
-0.34

это действительно мои две переменные, и значение синхронизируется с xml, перечисленным вверху.

ОБНОВЛЕНИЕ 2

Ну, я думал, что понял это, но я снова был неосторожен, и оказалось, что я не совсем решил проблему.Предыдущее решение закончилось записью всех данных в мои два словарных ключа, так что у меня есть два равных списка всех данных, назначенных двум различным словарным ключам.Идея состоит в том, чтобы иметь различные наборы данных, назначенные из XML для соответствующего ключа словаря.Вот текущий код:

# Import XML Parser
import xml.etree.ElementTree as ET

# Parse XML directly from the file path
tree = ET.parse(xml file)

# Create iterable item list
items = tree.findall('item')

# Create class for historic variables
class DataPoint:
    def __init__(self, low, high, freq):
        self.low = low
        self.high = high
        self.freq = freq

# Create Master Dictionary and variable list for historic variables
masterDictionary = {}
thisList = []

# Loop to assign variables as dictionary keys and associate their values with them
for item in items:
    thisKey = item.find('variable').text 
    masterDictionary[thisKey] = thisList
    if thisKey not in masterDictionary:
        masterDictionary[thisKey] = []
    newDataPoint = DataPoint(float(item.find('low').text), float(item.find('high').text), float(item.find('freq').text))
    thisList.append(newDataPoint)

Когда я ввожу:

print masterDictionary['stock'][5].low
print masterDictionary['inflation'][5].low
print len(masterDictionary['stock'])
print len(masterDictionary['inflation'])

результаты одинаковы для обеих клавиш («акции» и «инфляция»):

-.22
-.22
56
56

В файле XML есть 27 товаров с биркой и 29 с инфляцией.Как сделать так, чтобы каждый список, назначенный ключу словаря, извлекал только определенные данные в цикле?

ОБНОВЛЕНИЕ 3

Кажется, что работает с 2 циклами, но японятия не имею, как и почему это не будет работать в 1 одном цикле.Мне это удалось случайно:

# Import XML Parser
import xml.etree.ElementTree as ET

# Parse XML directly from the file path
tree = ET.parse(xml file)

# Create iterable item list
items = tree.findall('item')

# Create class for historic variables
class DataPoint:
    def __init__(self, low, high, freq):
        self.low = low
        self.high = high
        self.freq = freq

# Create Master Dictionary and variable list for historic variables
masterDictionary = {}

# Loop to assign variables as dictionary keys and associate their values with them
for item in items:
    thisKey = item.find('variable').text
    thisList = []
    masterDictionary[thisKey] = thisList

for item in items:
    thisKey = item.find('variable').text
    newDataPoint = DataPoint(float(item.find('low').text), float(item.find('high').text), float(item.find('freq').text))
    masterDictionary[thisKey].append(newDataPoint)

Я пробовал большое количество перестановок, чтобы это произошло за один цикл, но не повезло.Я могу получить все данные, перечисленные в обоих ключах - идентичные массивы всех данных (не очень полезные) или данные, отсортированные правильно в 2 отдельных массива для обоих ключей, но только последний отдельный ввод данных (цикл перезаписывает сам себя)каждый раз оставляя только одну запись в массиве).

Ответы [ 3 ]

2 голосов
/ 21 июля 2011

У вас серьезная проблема с отступами после (ненужного) else: pass. Исправьте это и попробуйте снова. Возникает ли проблема с вашими образцами входных данных? другие данные? Первый раз в цикле? Какое значение thisKey вызывает проблему [подсказка: об этом сообщается в сообщении об ошибке KeyError]? Каково содержимое masterDictionary перед тем, как происходит ошибка [подсказка: разбросайте несколько print операторов вокруг вашего кода]?

Другие замечания, не относящиеся к вашей проблеме:

Вместо if thisKey in masterDictionary == False: рассмотрите возможность использования if thisKey not in masterDictionary: ... сравнения с True или False почти всегда избыточны и / или немного "запаха кода".

Соглашение Python заключается в резервировании имен с начальной заглавной буквой (например, Item) для классов.

Использование только одного пробела на уровень отступа делает код практически неразборчивым и серьезно устарел. Всегда используйте 4 (если у вас нет веских причин - но я никогда не слышал об этом).

Обновление Я был не прав: thisKey in masterDictionary == False хуже, чем я думал; Поскольку in является реляционным оператором, используется цепное вычисление (например, a <= b < c), поэтому у вас есть (thisKey in masterDictionary) and (masterDictionary == False), который всегда будет иметь значение False, и, следовательно, словарь никогда не обновляется. Исправление, как я предложил: используйте if thisKey not in masterDictionary:

Также похоже, что thisList (инициализировано, но не используется) должно быть thisSublist (использовано, но не инициализировано).

0 голосов
/ 21 июля 2011

В вашем операторе if есть ошибка внутри цикла for. Вместо

if thisKey in masterDictionary == False:

запись

if (thisKey in masterDictionary) == False:

Учитывая оставшуюся часть исходного кода, вы сможете получить доступ к данным следующим образом:

masterDictionary['stock'][0].freq

Джон Мачин делает несколько правильных замечаний относительно стиля и запаха (и вы должны подумать о его предлагаемых изменениях), но эти вещи придут со временем и опытом.

0 голосов
/ 21 июля 2011

Изменение:

if thisKey in masterDictionary == False:

до

if thisKey not in masterDictionary:

Похоже, именно поэтому вы получили эту ошибку. Кроме того, вам нужно назначить что-то для thisSublist, прежде чем пытаться добавить его. Попробуйте:

thisSublist = []
thisSublist.append(newDataPoint)
...