Я постараюсь сделать этот вопрос простым, чтобы, надеюсь, эта концепция была применима и к другим областям.
Я работаю с наборами сейсмических данных, где N землетрясений зарегистрировано M сейсмическими станциями. Существует информация о землетрясении (идентификатор землетрясения, магнитуда и т. д.) и информация о конкретной станции (идентификатор станции, частота дискретизации приборов и т. д.). Не все сейсмические станции регистрируют все землетрясения, поэтому существует разное количество станций, регистрирующих каждое землетрясение.
В настоящее время я организую эти данные в объекте Pandas DataFrame, по одной строке на каждое землетрясение. Поскольку для каждого землетрясения существует разное количество станций, я сохраняю идентификаторы станций в виде массива numpy. Вот простой пример: землетрясения 0001 и 0002 магнитудой 2,1 и 3,1 соответственно. Четыре сейсмические станции: a, b, c и d имеют частоту дискретизации 100, 100, 60 и 60 соответственно.
import numpy as np
import pandas as pd
events = {
'event_id': ['0001', '0002'],
'mag': [2.1, 3.1],
'station_ids': [np.array(['a', 'c']), np.array(['a', 'b', 'c', 'd'])],
'station_sampling_rate': [np.array([100, 60]), np.array([100, 100, 60, 60])]
}
events = pd.DataFrame(events)
print(events)
что приводит к
event_id mag station_ids station_sampling_rate
0 0001 2.1 [a, c] [100, 60]
1 0002 3.1 [a, b, c, d] [100, 100, 60, 60]
Теперь, когда мне нужна информация о конкретной станции из этого DataFrame, мне нужно либо:
events, выполните некоторую проверку и сравните с существующим каталогом станций (медленно).events таким образом, чтобы он содержал все больше информации, специфичной для каждой станции (events становится действительно большим), и при этом циклично перебирал каждую строку events.Метод 1 до сих пор работал у меня, но он медленный. Метод 2 кажется пустой тратой ресурсов.
Желаемая структура приведенного выше примера такова:
station_id sampling_rate event_ids mag
0 a 100 [0001, 0002] [2.1, 3.1]
1 b 100 [0002] [3.1]
2 c 60 [0001, 0002] [2.1, 3.1]
3 d 60 [0002] [3.1]
Существует ли эффективный способ структурировать, хранить и преобразовывать эти данные? Кажется, уже должно быть что-то, что может работать с данными такого типа.
Я пробовал искать, но не знаю, как называется эта структура данных и есть ли у нее имя.
Доступ к вашему DataFrame таким образом (как и предполагалось) обеспечит лучшую оптимизацию производительности, чем вы могли бы разумно ожидать от любого решения на основе циклов. Отдельно я бы не стал беспокоиться о размере events, если только у вас нет действительно веской причины для этого, поскольку pandas оптимизирован для обработки наборов данных, которые, вероятно, больше по размеру, чем ваш (хотя без дополнительной информации об этом мы можем Не могу утвердительно сказать, обоснованы ваши опасения или нет). (2/2)
Также не забывайте, что приведение вашего DataFrame в более нормализованное состояние не должно быть болезненным, если вы можете использовать инструменты, которые pandas дают вам - соответствующий поток SO (3/2)
Кстати, я был бы склонен назвать это «денормализованным» - поскольку нормализованное представление, скорее всего, будет состоять из нескольких таблиц (одна содержит станции, другая содержит события со столбцами Station_id, Even_id, возможно, mag). У вас должна быть возможность эффективно хранить это в parquet, поскольку он позволяет использовать поля списка или структуры (или списка структур).
Но я согласен с предыдущими комментариями, если только у вас не возникнут проблемы с производительностью — храните и манипулируйте как обычно. А если у вас возникнут проблемы с производительностью, вы, вероятно, сможете их исправить, используя Polars/Duckdb или другие параметры, сохраняя при этом нормализованные данные.
Отлично, спасибо всем. Я новичок в пандах и базах данных, но эта концепция нормализации — именно то, что я искал, но у меня не было слова.






Цикл по строкам в Pandas по своей сути очень медленный и (почти) никогда не нужен. Для приведенного примера:
events2 = events.explode(['station_ids', 'station_sampling_rate'])
results = events2.groupby(['station_ids', 'station_sampling_rate'], as_index = False)[['mag', 'event_id']].agg(list)
print(results)
дает DF:
station_ids station_sampling_rate mag event_id
0 a 100 [2.1, 3.1] [0001, 0002]
1 b 100 [3.1] [0002]
2 c 60 [2.1, 3.1] [0001, 0002]
3 d 60 [3.1] [0002]
Работает отлично, спасибо.
№2, как вы описали, обычно считается стандартом, особенно если принять во внимание, как выглядит концепция нормализации в традиционных системах реляционных баз данных. Однако ваше утверждение «по-прежнему просматриваете каждую строку событий» сигнализирует о том, что вы не до конца понимаете выбранный вами инструмент (
pandas). Грубо говоря, существует очень мало причин, по которым вам когда-либо придется повторятьDataFrame(и если вы обнаружите, что вам нужно делать это часто, вполне вероятно, что вы выбрали совершенно неправильную структуру данных). Используйте его синтаксис правильно, напримерdf[df['station_id'] == 'a']для строк станцииa. (1/2)