Проблема с PyTables - разные результаты при переборе подмножества таблицы
Вопрос
Я новичок в PyTables и собираюсь использовать его для обработки данных, сгенерированных в результате моделирования на основе агентов и сохраненных в HDF5.Я работаю с тестовым файлом размером 39 МБ и испытываю некоторую странность.Вот макет таблицы:
/example/agt_coords (Table(2000000,)) ''
description := {
"agent": Int32Col(shape=(), dflt=0, pos=0),
"x": Float64Col(shape=(), dflt=0.0, pos=1),
"y": Float64Col(shape=(), dflt=0.0, pos=2)}
byteorder := 'little'
chunkshape := (20000,)
Вот как я получаю к нему доступ на Python:
from tables import *
>>> h5file = openFile("alternate_hose_test.h5", "a")
h5file.root.example.agt_coords
/example/agt_coords (Table(2000000,)) ''
description := {
"agent": Int32Col(shape=(), dflt=0, pos=0),
"x": Float64Col(shape=(), dflt=0.0, pos=1),
"y": Float64Col(shape=(), dflt=0.0, pos=2)}
byteorder := 'little'
chunkshape := (20000,)
>>> coords = h5file.root.example.agt_coords
Теперь вот где все становится странным.
[x for x in coords[1:100] if x['agent'] == 1]
[(1, 25.0, 78.0), (1, 25.0, 78.0)]
>>> [x for x in coords if x['agent'] == 1]
[(1000000, 25.0, 78.0), (1000000, 25.0, 78.0)]
>>> [x for x in coords.iterrows() if x['agent'] == 1]
[(1000000, 25.0, 78.0), (1000000, 25.0, 78.0)]
>>> [x['agent'] for x in coords[1:100] if x['agent'] == 1]
[1, 1]
>>> [x['agent'] for x in coords if x['agent'] == 1]
[1, 1]
Я не понимаю, почему значения искажаются, когда я перебираю всю таблицу, но не тогда, когда я беру небольшое подмножество из всего набора строк.Я уверен, что это ошибка в том, как я использую библиотеку, поэтому я был бы чрезвычайно признателен за любую помощь в этом вопросе.
Решение
Это очень распространенный момент путаницы при повторении Table
объект,
Когда вы перебираете Table
тип элемента, который вы получаете, - это не данные в элементе, а средство доступа к таблице в текущей строке.Так что с
[x for x in coords if x['agent'] == 1]
вы создаете список средств доступа к строке, которые все указывают на "текущую" строку таблицы, последнюю строку.Но когда ты делаешь
[x["agent"] for x in coords if x['agent'] == 1]
вы используете средство доступа при построении списка.
Решение для получения всех необходимых данных при построении списка с помощью средства доступа на каждой итерации.Есть два варианта
[x[:] for x in coords if x['agent'] == 1]
или
[x.fetch_all_fields() for x in coords if x['agent'] == 1]
Первый создает список кортежей.Последний возвращает объект NumPy void.IIRC, второй способ быстрее, но первый может иметь больше смысла для ваших целей.
Вот хорошее объяснение от разработчика PyTables. В будущих версиях при печати объекта доступа к строке могут не просто отображаться данные, а указываться, что это объект доступа к строке.