mar*_*lli 10 python pandas python-polars
假设我的数据如下所示:
data = {
'value': [1,9,6,7,3, 2,4,5,1,9]
}
Run Code Online (Sandbox Code Playgroud)
对于每一行,我想找到比当前元素大的最新前一个元素的行号。
所以,我的预期输出是:
[None, 0, 1, 2, 1, 1, 3, 4, 1, 0]
Run Code Online (Sandbox Code Playgroud)
1
没有前一个元素,所以我想None
在结果中9
至少比它之前的所有元素一样大,所以我想0
在结果中6
前一个元素9
比它大。他们之间的距离是1
。所以,我想要1
在这里的结果。我知道我可以在 Python 中循环执行此操作(如果我编写扩展,则可以在 C/Rust 中)。
我的问题:是否可以完全使用数据帧操作来解决这个问题?熊猫或者北极熊,都可以。但仅限数据帧操作。
因此,请不要执行以下操作:
apply
map_elements
map_rows
iter_rows
很难向量化此类问题,但您可以使用numba模块来加速任务。这个问题也可以很容易地并行化:
from numba import njit, prange
@njit(parallel=True)
def get_values(values):
out = np.zeros_like(values, dtype=np.float64)
for i in prange(len(values)):
idx = np.int64(i)
v = values[idx]
while idx > -1 and values[idx] <= v:
idx -= 1
if idx > -1:
out[i] = i - idx
out[0] = np.nan
return out
data = {
"value": [1, 9, 6, 7, 3, 2, 4, 5, 1, 9],
"out": [None, 0, 1, 2, 1, 1, 3, 4, 1, 0],
}
df = pd.DataFrame(data)
df["out2"] = get_values(df["value"].values)
print(df)
Run Code Online (Sandbox Code Playgroud)
印刷:
value out out2
0 1 NaN NaN
1 9 0.0 0.0
2 6 1.0 1.0
3 7 2.0 2.0
4 3 1.0 1.0
5 2 1.0 1.0
6 4 3.0 3.0
7 5 4.0 4.0
8 1 1.0 1.0
9 9 0.0 0.0
Run Code Online (Sandbox Code Playgroud)
基准(1-100 之间有 1_000_000 个项目):
from timeit import timeit
data = {
"value": np.random.randint(1, 100, size=1_000_000),
}
df = pd.DataFrame(data)
t = timeit('df["out"] = get_values(df["value"].values)', globals=globals(), number=1)
print(t)
Run Code Online (Sandbox Code Playgroud)
在我的机器 (AMD 5700x) 上打印:
0.3559090679627843
Run Code Online (Sandbox Code Playgroud)
我猜您正在寻找在 Rust 中实现的算法部分,所以我向您建议以下内容:
\nimport pandas as pd\nimport time\nimport numpy as np\n\ndata = {\n \'value\': [1, 9, 6, 7, 3, 2, 4, 5, 1, 9]\n}\ndf = pd.DataFrame(data)\n\nvalues = df[\'value\'].tolist()\n\n\nstart = time.time()\n### Algorithm for implementation in Rust, C ...\n_max = values[0]\nr = [None]\nfor i in range(1, len(values)):\n prev = values[:i+1][:-1]\n last = values[:i+1][-1]\n dist=0\n _max = max(prev) if last >= _max else _max\n for j in range(len(prev)-1, -1, -1):\n if last < _max:\n dist+=1\n else:\n r.append(dist)\n break\n if last < prev[j]:\n r.append(dist)\n break\nend = time.time()\n\nprint(end-start)\nprint(r)\n
Run Code Online (Sandbox Code Playgroud)\n[None, 0, 1, 2, 1, 1, 3, 4, 1, 0]\n
Run Code Online (Sandbox Code Playgroud)\n要在 Rust、Python 或其他语言中计算后在数据帧中实现计算:
\n[None, 0, 1, 2, 1, 1, 3, 4, 1, 0]\n
Run Code Online (Sandbox Code Playgroud)\n value out\n0 1 NaN\n1 9 0.0\n2 6 1.0\n3 7 2.0\n4 3 1.0\n5 2 1.0\n6 4 3.0\n7 5 4.0\n8 1 1.0\n9 9 0.0\n
Run Code Online (Sandbox Code Playgroud)\nRust 实现(参见 PyO3):
\n(应保留Python算法的先验逻辑)
\n在线编译器:https://play.rust-lang.org/?version =stable&mode=debug&edition=2021
\ndf[\'out\'] = r\n\nprint(df)\n
Run Code Online (Sandbox Code Playgroud)\n结果(在线测试):
\nTime elapsed is: 5.02\xc2\xb5s\n[None, Some(0), Some(1), Some(2), Some(1), Some(1), Some(3), Some(4), Some(1), Some(0)]\n
Run Code Online (Sandbox Code Playgroud)\n笔记 :
\n要在 Rust 中并行化任务,您可以使用radius.rayon
它提供的并行迭代器来并行化许多数据处理任务。
归档时间: |
|
查看次数: |
895 次 |
最近记录: |