极性从n列中减去numpy 1xn数组

eiee3dmh  于 2023-02-23  发布在  其他
关注(0)|答案(4)|浏览(142)

我在处理极坐标。我有一个 Dataframe 和一个numpy数组。我想减去它们。

import polars as pl
import pandas as pd

df = pl.DataFrame(np.random.randn(6, 4), schema=['#', 'x', 'y', 'z'])

arr = np.array([-10, -20, -30])

df.select(
    pl.col(r'^[x|y|z]$')
).apply(
    lambda x: np.array(x) - arr
)

shape: (6, 3)
┌───────────┬───────────┬───────────┐
│ column_0  ┆ column_1  ┆ column_2  │
│ ---       ┆ ---       ┆ ---       │
│ f64       ┆ f64       ┆ f64       │
╞═══════════╪═══════════╪═══════════╡
│ 10.143819 ┆ 21.875335 ┆ 29.682364 │
│ null      ┆ null      ┆ null      │
│ null      ┆ null      ┆ null      │
│ null      ┆ null      ┆ null      │
│ null      ┆ null      ┆ null      │
│ null      ┆ null      ┆ null      │
└───────────┴───────────┴───────────┘

所以现在减法只应用于第一行。
但如果我试着计算范数,那么它对每一行都有效:

df.select(
    pl.col(r'^[x|y|z]$')
).apply(
    lambda x: np.sum((np.array(x) - arr)**2)**0.5
)
shape: (6, 1)
┌───────────┐
│ apply     │
│ ---       │
│ f64       │
╞═══════════╡
│ 38.242255 │
│ 37.239545 │
│ 38.07624  │
│ 36.688312 │
│ 38.419194 │
│ 36.262196 │
└───────────┘

# check if it is correct:
np.sum((df.to_pandas()[['x', 'y', 'z']].to_numpy() - arr)**2, axis=1) ** 0.5
>>> array([38.24225488, 37.23954478, 38.07623986, 36.68831161, 38.41919409,
       36.2621962 ])

Pandas可以这样做:

df.to_pandas()[['x', 'y', 'z']] - arr

x   y   z
0   10.143819   21.875335   29.682364
1   10.360651   21.116404   28.871060
2   9.777666    20.846593   30.325185
3   9.394726    19.357053   29.716592
4   9.223525    21.618511   30.390805
5   9.751234    21.667080   27.393393

一种有效的方法是对每一列单独进行,但这意味着很多代码是相同的,尤其是当列数增加时:

df.select(
    pl.col('x') - arr[0], pl.col('y') - arr[1], pl.col('z') - arr[2]
)
1dkrff03

1dkrff031#

在这个问题上有几件事。
第一个问题是,除非您正在执行自定义python函数,否则您真的不希望使用apply
apply表达式将列的元素传递给python函数。2注意你现在运行的是python,这会很慢。
没有一个真正的polars方法来做你想做的事情。当polars看到pl.col(r'^[x|y|z]$').expr时,它会识别出符合正则表达式的每一列,然后会有一个线程来完成表达式的其余部分。表达式不知道它在顺序中的位置。它只知道它的数据是什么,以及它应该做什么。因此,您无法在expr中放置任何内容,使其知道要访问数组中的哪个元素。
为了得到你想要的,你必须做一些类似于@ignoring_gravity had的事情,但是你可以使用re模块。

import re
df.select(pl.col(col)-arr[i] 
          for i, col in enumerate(filter(re.compile(r'^[x|y|z]$').match, df.columns)))
4xrmg8kj

4xrmg8kj2#

您可以匹配Pandas输出

In [15]: df.to_pandas()[['x', 'y', 'z']] - arr
Out[15]:
           x          y          z
0  10.342991  21.258934  29.083287
1  10.136803  21.543558  28.168207
2  11.900141  19.557348  29.490541
3   9.192346  19.498689  28.195094
4   9.219745  20.330358  29.005278
5  11.853378  19.458095  30.357041

In [17]: df.select([pl.col(col)-arr[i] for i, col in enumerate(['x', 'y', 'z'])])
Out[17]:
shape: (6, 3)
┌───────────┬───────────┬───────────┐
│ x         ┆ y         ┆ z         │
│ ---       ┆ ---       ┆ ---       │
│ f64       ┆ f64       ┆ f64       │
╞═══════════╪═══════════╪═══════════╡
│ 10.342991 ┆ 21.258934 ┆ 29.083287 │
│ 10.136803 ┆ 21.543558 ┆ 28.168207 │
│ 11.900141 ┆ 19.557348 ┆ 29.490541 │
│ 9.192346  ┆ 19.498689 ┆ 28.195094 │
│ 9.219745  ┆ 20.330358 ┆ 29.005278 │
│ 11.853378 ┆ 19.458095 ┆ 30.357041 │
└───────────┴───────────┴───────────┘
cgh8pdjw

cgh8pdjw3#

避免re导入的另一个选项是:

res = df.select(
    pl.col(col) - c
    for col, c in zip(df.select(pl.col(r'^[x|y|z]$')).columns, arr)
)

这对于非常小的 Dataframe 来说稍微慢一些(我猜是因为它受正则表达式速度的支配),但是对于较大的 Dataframe 来说同样快。

jexiocij

jexiocij4#

我看到了一小段时间的答案,我正在寻找,但评论被删除。
解决方案是返回一个元组:

df.select(
    pl.col(r'^[x|y|z]$')
).apply(
    # lambda x: np.array(x) - arr  # old code
    lambda x: tuple(np.array(x) - arr)  # new code
)

相关问题