Как вставить массивы в базу данных?
В моем предыдущем вопросе многие пользователи хотели, чтобы я дал несколько дополнительных данных для игры. Поэтому я работал над экспортом всех моих данных и обработкой его с помощью Python, но потом понял: где я могу оставить все эти данные?
Ну, я решил, что лучше всего будет вставлять их в базу данных, так что по крайней мере у меня нет для синтаксического анализа необработанных файлов каждый раз. Но так как я ничего не знаю о базах данных, это выглядит довольно запутанным. Я пробовал некоторые учебные пособия для создания базы данных sqlite, добавления таблицы и поля и попытки вставить мой numpy.arrays, но он не может заставить его работать.
Обычно мои результаты для каждой собаки выглядят так:
![alt text]()
Итак, у меня есть 35 разных собак, и у каждой собаки есть 24 измерения. Каждое измерение имеет неизвестное количество контактов. Каждое измерение состоит из трехмерного массива (248 кадров всей пластины [255x63]) и 2D-матрицы (максимальные значения для каждого датчика пластины [255x63]). Хранение одного значения в базе данных не было проблемой, но получение моих 2D-массивов там не работало.
Итак, мой вопрос: как мне заказать это в базе данных и вставить в него мои массивы?
Ответы
Ответ 1
Вы, вероятно, захотите начать с таблицы dogs
, содержащей все плоские (не массивные) данные для каждой собаки, вещи, которые у каждой собаки есть, например имя, пол и возраст:
CREATE TABLE `dogs` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(64),
`age` INT UNSIGNED,
`sex` ENUM('Male','Female')
);
Оттуда у каждой собаки есть "много" измерений, поэтому вам нужна таблица dog_mesaurements
для хранения 24 измерений:
CREATE TABLE `dog_measurements` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`dog_id` INT UNSIGNED NOT NULL,
`paw` ENUM ('Front Left','Front Right','Rear Left','Rear Right'),
`taken_at` DATETIME NOT NULL
);
Затем, когда вы делаете измерение, вы INSERT INTO dog_measurements (dog_id,taken_at) VALUES (*?*, NOW());
где *? * - идентификатор собаки из таблицы dogs
.
Затем вам понадобятся таблицы для хранения фактических кадров для каждого измерения, например:
CREATE TABLE `dog_measurement_data` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`dog_measurement_id` INT UNSIGNED NOT NULL,
`frame` INT UNSIGNED,
`sensor_row` INT UNSIGNED,
`sensor_col` INT UNSIGNED,
`value` NUMBER
);
Таким образом, для каждого из 250 кадров вы проходите через каждый из 63 датчиков и сохраняете значение для этого датчика с номером кадра в базе данных:
INSERT INTO `dog_measurement_data` (`dog_measurement_id`,`frame`,`sensor_row`,`sensor_col`,`value`) VALUES
(*measurement_id?*, *frame_number?*, *sensor_row?*, *sensor_col?*, *value?*)
Очевидно, замените measure_id?, frame_number?, sensor_number?, value? с реальными значениями: -)
Таким образом, каждый dog_measurement_data
является единственным значением датчика для данного кадра. Таким образом, чтобы получить все значения датчиков для всего заданного кадра, вы должны:
SELECT `sensor_row`,sensor_col`,`value` FROM `dog_measurement_data`
WHERE `dog_measurement_id`=*some measurement id* AND `frame`=*some frame number*
ORDER BY `sensor_row`,`sensor_col`
И это даст вам все строки и столбцы для этого фрейма.
Ответ 2
Django имеет библиотеку для инкапсуляции всей работы базы данных в классы Python, поэтому вам не нужно связываться с сырым SQL пока вы не будете делать что-то действительно умное. Несмотря на то, что Django является основой для веб-приложений, вы можете использовать ORM базы данных.
Модели Josh будут выглядеть в Python с помощью Django:
from django.db import models
class Dog(models.Model):
# Might want to look at storing birthday instead of age.
# If you track age, you probably need another field telling
# you when in the year age goes up by 1... and at that point,
# you're really storing a birthday.
name = models.CharField(max_length=64)
age = models.IntegerField()
genders = [
('M', 'Male'),
('F', 'Female'),
]
gender = models.CharField(max_length=1, choices=genders)
class Measurement(models.Model):
dog = models.ForeignKey(Dog, related_name="measurements")
paws = [
('FL', 'Front Left'),
('FR', 'Front Right'),
('RL', 'Rear Left'),
('RR', 'Rear Right'),
]
paw = models.CharField(max_length=2, choices=paws)
taken_at = models.DateTimeField(default=date, auto_now_add=True)
class Measurement_Point(models.Model):
measurement = models.ForeignKey(Measurement, related_name="data_points")
frame = models.IntegerField()
sensor_row = models.PositiveIntegerField()
sensor_col = models.PositiveIntegerField()
value = models.FloatField()
class Meta:
ordering = ['frame', 'sensor_row', 'sensor_col']
Поля id
создаются автоматически.
Затем вы можете делать такие вещи, как:
dog = Dog()
dog.name = "Pochi"
dog.age = 3
dog.gender = 'M'
# dog.gender will return 'M', and dog.get_gender_display() will return 'Male'
dog.save()
# Or, written another way:
dog = Dog.objects.create(name="Fido", age=3, sex='M')
Чтобы выполнить измерение:
measurement = dog.measurements.create(paw='FL')
for frame in range(248):
for row in range(255):
for col in range(63):
measurement.data_points.create(frame=frame, sensor_row=row,
sensor_col=col, value=myData[frame][row][col])
Наконец, чтобы получить кадр:
# For the sake of argument, assuming the dogs have unique names.
# If not, you'll need some more fields in the Dog model to disambiguate.
dog = Dog.objects.get(name="Pochi", sex='M')
# For example, grab the latest measurement...
measurement = dog.measurements.all().order_by('-taken_at')[0]
# `theFrameNumber` has to be set somewhere...
theFrame = measurement.filter(frame=theFrameNumber).values_list('value')
Примечание: это вернет список кортежей (например, [(1.5,), (1.8,), ... ]
), так как values_list()
может сразу извлекать сразу несколько полей. Я не знаком с NumPy, но я бы предположил, что у него есть функция, аналогичная функции Matlab reshape
для переназначения векторов на матрицы.
Ответ 3
Я думаю, что вы не можете понять, как разместить 2D-данные в базе данных.
Если вы думаете о соотношении между двумя столбцами, вы можете рассматривать его как 2D-данные с 1-м столбцом как данные оси X и 2-й столбец как данные оси Y. Аналогично для 3D-данных.
Наконец, ваш db должен выглядеть так:
Table: Dogs
Columns: DogId, DogName -- contains data for each dog
Table: Measurements
Columns: DogId, MeasurementId, 3D_DataId, 2D_DataId -- contains measurements of each dog
Table: 3D_data
Columns: 3D_DataId, 3D_X, 3D_Y, 3D_Z -- contains all 3D data of a measurement
Table: 2D_data
Columns: 2D_DataId, 2D_X, 2D_Y -- contains all 2D data of a measurement
Также вы можете захотеть сохранить 3D-данные и данные 2D в заказе. В этом случае вам нужно будет добавить столбец для хранения этого порядка в таблице трехмерных данных и 2D-данных
Ответ 4
Единственное, что я хотел бы добавить к ответу Джоша, это то, что если вам не нужно запрашивать отдельные кадры или датчики, просто храните массивы в виде BLOB в таблице dog_measurement_data. Я сделал это раньше с большим двоичным набором данных датчика, и это получилось хорошо. Вы в основном запрашиваете 2d и 3d массивы с каждым измерением и обрабатываете их в коде вместо базы данных.
Ответ 5
Я много выиграл от sqlalchemy
package; это объектный реляционный сопоставитель. Это означает, что вы можете создать очень четкое и четкое разделение между вашими объектами и вашими данными:
Базы данных SQL ведут себя как объект коллекции больше размера и производительность начинает иметь значение; объект коллекции ведут себя как таблицы и строки больше начинается абстракция имеет значения. SQLAlchemy направлена на учитывать оба эти принципа.
Вы можете создавать объекты, представляющие ваши разные существительные (Dog, Measurement, Plate и т.д.). Затем вы создаете таблицу через конструкторы sqlalchemy
, которая будет содержать все данные, которые вы хотите связать, например, с объектом Dog
. Наконец, вы создаете mapper
между объектом Dog
и dog_table
.
Это трудно понять без примера, и я не буду воспроизводить его здесь. Вместо этого, пожалуйста, начните с чтения данного примера, а затем изучите этот учебник.
Как только вы сможете думать о своих Dogs
и Measurements
, как вы это делаете в реальном мире (то есть сами объекты), вы можете начать факторинг данных, которые их создают.
Наконец, постарайтесь не вступать в брак с вашими данными в определенном формате (как в настоящее время, используя массивы numpy
). Вместо этого вы можете думать о простых числах, а затем преобразовывать их по требованию в конкретный формат, который требует ваше текущее приложение (в соответствии с парадигмой Model-View-Controller).
Удачи!
Ответ 6
Из вашего описания я настоятельно рекомендую заглянуть в PyTables. Это не реляционная база данных в традиционном смысле, она имеет большинство функций, которые вы, вероятно, будете использовать (например, запрос), позволяя легко хранить большие многомерные наборы данных и их атрибуты. В качестве дополнительного бонуса он тесно интегрирован с numpy.