Как использовать функцию numpy для добавления столбца данных polars

Это продолжение моего предыдущего вопроса Пользователь glebcom помог мне с переносом координат из строки в список значений float64. В ответе я нашел 2 метода, как рассчитать расстояние между координатами:

  1. используя формулу numpy.linalg.norm (a-b)
  2. используя расстояние импорта scipy.spatial: dst = Distance.euclidean(a, b) Как применить одну из этих формул для расчета расстояния между координатами из столбцов c и d из фрейма данных polars
import polars as pl
from scipy.spatial import distance
import numpy as np
pl.Config.set_fmt_str_lengths(2000)
data = {"a": ["782.83    7363.51    6293    40   PD","850.68    7513.1    6262.17    40   PD"], "b": ["795.88    7462.65    6293    40   PD","1061.64    7486.08    6124.85    40   PD"]}
df=pl.DataFrame(data)
df=df.with_columns([
    pl.col("a").str.replace_all(r" +", " ")\
        .str.split(" ").arr.slice(0,3)\
        .cast(pl.List(pl.Float64)).alias("c"),\
    pl.col("b").str.replace_all(r" +", " ")\
        .str.split(" ").arr.slice(0,3)\
        .cast(pl.List(pl.Float64)).alias("d")\
])
print(df)

Мои попытки были

df=df.with_columns(np.linalg.norm(pl.col("C")-pl.col("d")).alias("distance"))
or
df=df.with_columns(distance(pl.col("C"),pl.col("d")).alias("distance"))

но ничего из вышеперечисленного не работает. Заранее спасибо за вашу помощь.

Артур

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
114
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы не сможете вызвать numpy.linalg.norm непосредственно в своем фрейме данных polars. Он ожидает пустой массив формы (N, n) (где N — ваше количество точек, а n — ваше число измерений, 3).

Вы можете подготовить данные самостоятельно, передать их в numpy и вернуть результаты в поляры.

Сначала вычислите разницу между координатами двух ваших точек по всем трем измерениям:

diffs = df.select(
    [
        (pl.col("c").arr.get(i) - pl.col("d").arr.get(i)).alias(f"diff_{i}")
        for i in range(3)
    ]
)
┌─────────┬────────┬────────┐
│ diff_0  ┆ diff_1 ┆ diff_2 │
│ ---     ┆ ---    ┆ ---    │
│ f64     ┆ f64    ┆ f64    │
╞═════════╪════════╪════════╡
│ -13.05  ┆ -99.14 ┆ 0.0    │
│ -210.96 ┆ 27.02  ┆ 137.32 │
└─────────┴────────┴────────┘

Затем преобразуйте его в numpy и вызовите функцию:

import numpy.linalg
distance=numpy.linalg.norm(diffs.to_numpy(), axis=1)
pl.Series(distance).alias("distance")
┌────────────┐
│ distance   │
│ ---        │
│ f64        │
╞════════════╡
│ 99.99521   │
│ 253.161973 │
└────────────┘

В качестве альтернативы вы можете самостоятельно рассчитать евклидов продукт:

df.select(
    [
        (pl.col("c").arr.get(i) - pl.col("d").arr.get(i)).alias(f"diff_{i}") ** 2
        for i in range(3)
    ]
).sum(axis=1).sqrt()
┌────────────┐
│ distance   │
│ ---        │
│ f64        │
╞════════════╡
│ 99.99521   │
│ 253.161973 │
└────────────┘

PS: scipy.spatial.distance.euclidean не будет работать, потому что он работает только с одной точкой во времени, что сделало бы его очень медленным в полярах.

Решение с np.linalg.norm внутри map

def l2_norm(s: pl.Series) -> pl.Series:
    # 1) difference: c-d
    diff = s.struct.field("c").to_numpy() - s.struct.field("d").to_numpy()
    # 2) apply np.linalg.norm()
    return pl.Series(diff).apply(
        lambda x: np.linalg.norm(np.array(x))
    )

df.with_columns([
    pl.struct(["c", "d"]).map(l2_norm).alias("distance")
])
┌────────────┐
│ distance   │
│ ---        │
│ f64        │
╞════════════╡
│ 99.99521   │
│ 253.161973 │
└────────────┘

Спасибо за ответ. Жаль, что нельзя отметить два ответа как решения.

Artup 07.02.2023 00:34

Другие вопросы по теме