对智谱清言有点失望

86 天前
 NoOneNoBody

GLM-4 首先,它不知道“智谱清言”是什么,哈哈

“有一个 dataframe ,index 为整数,已经排序,所有值均为浮点类型,求其中两列,假设名为 a,b ,它们是否相交,a 上穿 b 为 1 ,a 下穿 b 为-1 ,无相交为 0 ,返回一个 series ,使用 Numba 加速” 这段话,chatgpt3.5 给我的是代码,智谱清言给我的是计算结果……结果,就是它自己生成了一个 datframe 并计算了,把结果回答给我,很晕

chatgpt3.5 虽然给我的代码是错的,但受它启发,写了个简单函数完成了,这个函数是向量化的

def is_cross(arr:np.ndarray, arr_ref:np.ndarray)->np.ndarray:
    '''
    求两个 array 是否有相交\n
    返回:一个 numpy array\n
    其中 0 表示没有相交,1 表示 arr 上穿 arr_ref ,-1 则表示下穿\n
    \n
    原理:求两个 array 的差并获取符号数列,求取这个符号数列相邻的差,再次获取这个差值数列的符号为返回结果\n
    相邻符号如果相同差为 0 ,就是无相交;符号从-变 0/+,为上穿,差值为+1/+2 ;符号从+变 0/-,为下穿,差值为-1/-2\n
    符号从 0 变为有符号,性质一样,结果也符合需求\n
    所以再次求取符号则为结果
    '''
    return np.sign(np.ediff1d(np.sign(arr-arr_ref), to_begin=0))
1161 次点击
所在节点    OpenAI
2 条回复
cwyalpha
85 天前
要解决这个问题,我们可以编写一个 Python 函数,该函数接受一个 DataFrame 和两列名作为输入,并返回一个 Series ,表示列`a`和列`b`的穿越情况。然后,我们将使用 Numba 装饰器`@jit`来加速这个函数。

1. **定义函数**:函数将遍历 DataFrame 的行,比较每一行的`a`和`b`列值与其上一行的值,以确定是否发生了上穿或下穿。
2. **使用 Numba 加速**:通过在函数定义前添加`@jit`装饰器来加速函数。Numba 是一个开源的 JIT ( Just-In-Time )编译器,它可以显著提高 Python 代码的执行速度,特别是对于数值计算和科学计算非常有效。
3. **返回 Series**:根据穿越情况,为每个时间点返回 1 (上穿)、-1 (下穿)或 0 (无相交)。

下面是实现这个逻辑的代码示例。首先,确保你已经安装了`numba`和`pandas`库。

```python
import pandas as pd
import numpy as np
from numba import jit

# 示例 DataFrame 创建,仅供参考
# df = pd.DataFrame({'a': np.random.rand(10), 'b': np.random.rand(10)})

@jit(nopython=True)
def calculate_cross_over(a, b):
result = np.zeros(len(a))
for i in range(1, len(a)):
if a[i] > b[i] and a[i-1] <= b[i-1]:
result[i] = 1 # a 上穿 b
elif a[i] < b[i] and a[i-1] >= b[i-1]:
result[i] = -1 # a 下穿 b
# 其他情况默认为 0 ,无需额外处理
return result

def cross_over_series(df, col_a, col_b):
a_values = df[col_a].values
b_values = df[col_b].values
cross_over_values = calculate_cross_over(a_values, b_values)
return pd.Series(cross_over_values, index=df.index)

# 使用函数的示例
# result_series = cross_over_series(df, 'a', 'b')
# print(result_series)
```

在这个代码中:
- `calculate_cross_over`函数是使用 Numba JIT 编译的核心函数,它负责计算两列之间的穿越情况。
- `cross_over_series`函数是一个封装函数,它接受 DataFrame 和列名作为输入,调用`calculate_cross_over`函数,并返回结果 Series 。

请注意,由于 Numba 的`nopython`模式限制,我们直接在 Numba 函数中使用了 Numpy 数组而不是直接操作 DataFrame 。这是因为 Numba 最优化地支持 Numpy 数组计算。




-------
能否向量化地完成这个代码
-------


向量化的方法可以使用 Pandas 和 Numpy 的内置功能来实现,而不需要显式循环,这样可以提高计算效率并简化代码。下面是如何使用向量化方法来完成相交点检测的步骤:

1. **计算差分**:首先,计算两列`a`和`b`的差分,即`a - b`。这将用于确定`a`是否在`b`之上或之下。
2. **标记穿越点**:通过比较相邻元素的差分符号,我们可以找到穿越点。当差分从负变正时,表示`a`上穿`b`;从正变负时,表示`a`下穿`b`。
3. **返回 Series**:最终,我们将创建一个 Series ,根据是否发生穿越以及穿越的方向来分配值( 1 代表上穿,-1 代表下穿,0 代表无穿越)。

下面是实现这个方法的代码示例:

```python
import pandas as pd
import numpy as np

def vectorized_cross_over(df, col_a, col_b):
# 计算 a 和 b 的差值
diff = df[col_a] - df[col_b]
# 计算差值的符号变化(正负变化),使用 np.sign(diff)获取符号,并通过 diff 计算其差分以检测变化
sign_changes = np.sign(diff).diff()

# 上穿为 1 ,下穿为-1 ,无穿越为 0
# np.sign(diff).diff() == 2 表示从负到正的变化,即上穿
# np.sign(diff).diff() == -2 表示从正到负的变化,即下穿
crossover_series = pd.Series(0, index=df.index) # 初始化为 0
crossover_series[sign_changes == 2] = 1 # 上穿
crossover_series[sign_changes == -2] = -1 # 下穿

return crossover_series

# 示例 DataFrame 创建
# df = pd.DataFrame({'a': np.random.rand(10), 'b': np.random.rand(10)})

# 使用函数
# result_series = vectorized_cross_over(df, 'a', 'b')
# print(result_series)
```

这段代码完全使用向量化操作来检测`a`和`b`列的穿越情况,避免了显式循环,从而提高了性能。需要注意的是,由于使用了`diff()`方法,第一个元素将总是被标记为 0 (无穿越),因为它没有前一个元素来比较。







GPT4 的回答不知道是否正确
NoOneNoBody
85 天前
@cwyalpha #1
原理是一样的,np.ediff1d 和 pd.Series.diff 是一样的,只是 np.ediff1d 计算少了第一个值,补个 to_begin=0 参数而已
我起初也是用 diff(),后来才改成兼容性更高的 numpy

不过这里 gpt 漏了一个逻辑,相邻两个其中一个是 0 ,另一个是+1/-1 ,这个 diff 结果是+1 或-1 ,不是+2/-2
用==2/==-2 会漏掉这个
0 就是两条线在同一个点刚好相等的情况,如 a=[1,2,3,4], b=[3,2,1,0],第二个点是刚好相等的

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1015728

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX