Я хочу сопоставить ключ в одном фрейме данных Polars с другой базой Polars DF на основе отношений между столбцами. Это всего лишь пример, полные DF1 и DF2 намного больше (2,5 миллиона и 1,5 миллиона строк соответственно.
DF1 = = pl.DataFrame({
'chr' : ["GL000008.2", "GL000008.2", "GL000008.2", "GL000008.2","GL000008.2", "GL000008.2"],
'start': [14516,17380,17381,20177,22254,24357],
'end': [14534,17399,17399,20195,22274,24377]
})
DF2 = = pl.DataFrame({
'key' : [1,2,3,4,5,6],
'chrom' : ["GL000008.2", "GL000008.2", "GL000008.2", "GL000008.2","GL000008.2", "GL000008.2"],
'start': [14516,15377,17376,20177,22254, 24357],
'end': [14534,15403,17399,20195,22274,24377]})
Я хочу:
DF1 = = pl.DataFrame({
'chr' : ["GL000008.2", "GL000008.2", "GL000008.2", "GL000008.2","GL000008.2", "GL000008.2"],
'start': [14516,17380,17381,20177,22254,24357],
'end': [14534,17399,17399,20195,22274,24377],
'key': [1,3,3,4,5,6]
})
Я хотел бы назначить key из DF2 в DF1, когда chrom соответствует chr, а start и end в DF1 содержатся в begin и end в DF2.
Сначала я попытался выполнить итерацию по строкам DF1, найдя соответствующую запись в DF2:
sz = len(DF1[:,0])
for i in range(sz):
DF1[i,"key"] = DF2.filter(
(pl.col("chrom") == DF1[i,"chr"])\
& (pl.col("begin") <= DF1[i,"start"])\
& (pl.col("end") >= DF1[i,"end"])
).select('key')[0,0]
Итерация строк через DF невероятно медленная. Это занимает около 10 часов.
Я также пытался использовать np.array вместо непосредственно в df. это немного быстрее, но все еще очень медленно.
Я ищу способ сделать это, используя собственную структуру данных Polar. У меня нет ключа для присоединения, поэтому стратегии join и join_asof не работают.
Поможет ли это? stackoverflow.com/a/73177515/20557510
Другой пример: github.com/pola-rs/polars/issues/5004#issuecomment-1259784083
@ignoring_gravity Я попытался добавить объяснение получше, извините.
@ ΩΠΟΚΕΚΡΥΜΜΕΝΟΣ, спасибо за ваши предложения — но у меня нет ключа, чтобы присоединиться — на самом деле это всего три условия. На самом деле ключом является то, что я пытаюсь установить в DF1, чтобы я мог выполнять соединения.
Спасибо @JimBeck - это все еще не воспроизводимо. Вы можете опубликовать что-нибудь, что мы можем скопировать и вставить?
@ignoring_gravity Я добавил фактические полные DF1 и DF2 по ссылке на репозиторий, чтобы их можно было скачать. Приведенный выше код можно запустить в этих файлах. Я не уверен, что еще я могу предоставить, чтобы скопировать и вставить.
Что-то вроде df1 = pl.DataFrame({'start': [14516, 14517, ...], 'end': [14712, ...]}), df2 = ... . Мы должны иметь возможность запускать ваш код без загрузки данных
@ignoring_gravity Спасибо за руководство. И просто для ясности - код, который я написал, работает - он чертовски медленный.
Join и filter должны дать вам то, что вам нужно:
(
df1.join(df2, left_on = "chr", right_on = "chrom")
.filter(
(pl.col("start") >= pl.col("start_right"))
& (pl.col("end") <= pl.col("end_right"))
)
.drop(["start_right", "end_right"])
)
shape: (6, 4)
┌────────────┬───────┬───────┬─────┐
│ chr ┆ start ┆ end ┆ key │
│ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ i64 ┆ i64 ┆ i64 │
╞════════════╪═══════╪═══════╪═════╡
│ GL000008.2 ┆ 14516 ┆ 14534 ┆ 1 │
│ GL000008.2 ┆ 17380 ┆ 17399 ┆ 3 │
│ GL000008.2 ┆ 17381 ┆ 17399 ┆ 3 │
│ GL000008.2 ┆ 20177 ┆ 20195 ┆ 4 │
│ GL000008.2 ┆ 22254 ┆ 22274 ┆ 5 │
│ GL000008.2 ┆ 24357 ┆ 24377 ┆ 6 │
└────────────┴───────┴───────┴─────┘
Спасибо за решение. Я думал, что не могу использовать объединение, потому что поле chr представляет собой отношение «многие ко многим» между DF1 и DF2.
Использование join_asof может обеспечить эффективное решение:
(
DF1
.sort('start')
.join_asof(
DF2.sort('start'),
by_left = "chr",
by_right = "chrom",
on = "start",
strategy = "backward")
.filter(
pl.col('end') <= pl.col('end_right')
)
)
shape: (6, 5)
┌────────────┬───────┬───────┬─────┬───────────┐
│ chr ┆ start ┆ end ┆ key ┆ end_right │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ i64 ┆ i64 ┆ i64 ┆ i64 │
╞════════════╪═══════╪═══════╪═════╪═══════════╡
│ GL000008.2 ┆ 14516 ┆ 14534 ┆ 1 ┆ 14534 │
│ GL000008.2 ┆ 17380 ┆ 17399 ┆ 3 ┆ 17399 │
│ GL000008.2 ┆ 17381 ┆ 17399 ┆ 3 ┆ 17399 │
│ GL000008.2 ┆ 20177 ┆ 20195 ┆ 4 ┆ 20195 │
│ GL000008.2 ┆ 22254 ┆ 22274 ┆ 5 ┆ 22274 │
│ GL000008.2 ┆ 24357 ┆ 24377 ┆ 6 ┆ 24377 │
└────────────┴───────┴───────┴─────┴───────────┘
Примечание: это предполагает, что ваши начальные и конечные интервалы в DF2 не перекрываются.
Можете ли вы сделать свой пример воспроизводимым и показать ожидаемый результат, пожалуйста?