【问题标题】:Handling wrapping of values in pandas处理 pandas 中值的包装
【发布时间】:2016-02-22 12:32:09
【问题描述】:

我正在处理来自位置传感器的数据,该传感器以角坐标(俯仰、滚动和偏航)报告。传感器读数使得最大读数为 180 度。越过这一点,读数就会跳到负数。例如,一系列轻微波动的读数可能类似于:

 178.8
 178.9
-178.8
-178.0
-179.0
 180.0
 179.0

我目前通过在循环中顺序检查所有值来处理这个问题。我得到两个连续读数之间的增量并保持运行总计以获得我当前的角位置。如果我从第三象限 (90

    Yaw = inData['Yaw']
    cum_sum = Yaw[0]
    for i in range(1, Yaw)):
        x_prev = Yaw[i-1]
        x = Yaw[i]
        if 90 <= x_prev and x_prev <= 180 and -180 <= x and x <= -90:
            x = x + 360
        elif -180 <= x_prev and x_prev <= -90 and 90 <= x and x <= 180:
            x = x - 360
        else:
            pass
        delta = x - x_prev
        cum_sum += delta

这里,inData 是一个数据框,其中包含来自多个轴的角度位置,“Yaw”是该数据框中的一个系列。

如果我可以对角度值进行一致的校正,我可以生成一系列增量并进行累积求和以获得位置。但是,将 360 添加到所有读数或将角度作为模 360 只会将翻转点从 +/-180 之间的交叉点移动到 0 和 360 之间的交叉点。

鉴于我已经在 DataFrame/Series 中获得了这些读数,我想知道是否有更 Pythonic(更快)的方法来做到这一点。

【问题讨论】:

  • 为什么不对小于零的值加360度?
  • 类似:inData.Yaw[inData.Yaw&lt;0.0] += 360.
  • 请注意,这也有效并且更具可读性:-180 &lt;= x &lt;= -90。鉴于 -180 是最小读数,您可以简单地使用 x &lt;= -90。但无论如何我都不会在循环中进行此计算。看看下面我的矢量化解决方案。
  • 将 360 添加到负数只会将翻转从第 3 和第 4 象限移动到第 1 和第 4 象限。想想在 1 度,然后在负方向移动 2 度。如果将 360 添加到第二个值,则不是从 1 度变为 -1 度,而是变为 -359 度。
  • 是的,复合条件句更具可读性。我猜,这只是我 C 天的遗留物。感谢您的建议。

标签: python pandas rollover


【解决方案1】:

全部矢量化,所以应该很快。

s = pd.Series([-178.8, 178.9, -178., -179., 180., 179.])

delta = (s.diff() + 
         (((s.shift() >= 90) & (s <= -90)).astype(int) - 
          ((s.shift() <= -90) & (s >= 90)).astype(int)) * 360)

>>> delta.cumsum()
0    NaN
1   -2.3
2    0.8
3   -0.2
4   -1.2
5   -2.2
dtype: float64

关于逻辑,如果测量值位于左上象限,((s.shift() &gt;= 90) &amp; (s &lt;= -90)).astype(int) 将评估为 1,否则评估为零。如果测量值位于右下象限,-((s.shift() &lt;= -90) &amp; (s &gt;= 90)).astype(int) 将评估为负一,否则为零。这是一种矢量化的方式,表示如果您在左上象限,则应将差值加 360,如果您在右下象限,则应从差值中减去 360,否则只取差值。

【讨论】:

  • 老实说:我在遵循逻辑时遇到了一些问题。此外,这些答案是不正确的。增量为 NaN、-2.3、3.1、-1、-1、-1。
  • 抱歉,让我先离开几分钟。
  • 这些是累积增量。如果您将上面的增量相加,您会看到结果是相同的。
  • 既然你解释了它,那是一段优雅的代码!谢谢!
  • 速度提升应该是巨大的。希望它对您有用。
【解决方案2】:

我认为 np.unwrap() 可以做你想做的事,而不必搞乱 deltas 和 cumsum。 Docs

In [120]: data = pd.Series([178.8, 178.9, -178.8, -178.0, -179.0, 180.0, 179.0])

In [121]: np.degrees(np.unwrap(np.radians(data)))
Out[121]: array([ 178.8,  178.9,  181.2,  182. ,  181. ,  180. ,  179. ])

它处理多个环绕:

In [124]: np.degrees(np.unwrap(np.radians(data + 540)))
Out[124]: array([ 718.8,  718.9,  721.2,  722. ,  721. ,  720. ,  719. ])

【讨论】:

  • 聪明!老实说,np.unwrap() 是我不知道存在的那些函数之一。
【解决方案3】:

如果我理解你的话,象限是这样的(顺时针方向):

  • 1st:-90 到 0 度。
  • 第二个:从 0 到 90 度
  • 3rd:从 90 到 180 度。
  • 4th:从 -180 到 90 度。

如果是这样的话,我建议你先把你的讲座改成传统的 360 度测量:

def parseSensorReading(readingDegrees):
    if readingDegrees < 0:
        degrees360 = readingDegrees + 360
    degrees360 = readingDegrees
    return degrees360

然后检测你正在读取的象限:

def getQuadrant(degrees360):
    if degrees360 < 360:
        quadrant = 1
    if degrees360 < 270:
        quadrant = 4
    if degrees360 < 180:
        quadrant = 3
    if degrees360 < 90:
        quadrant = 2
    return quadrant

有了象限,现在您可以计算增量:

def getDelta(x_old, x_new):
    q_old = getQuadrant(x_old)
    q_new = getQuadrant(x_new)
    if q_old == 1 and q_new == 2:
        delta = (x_new + 360) - x_old
    else:
        delta = x_new - x_old

最后,你的代码变成了:

yaw = inData["Yaw"]
cumSum = yaw[0]
for i in range(1, len(yaw) + 1)):
    x_old = parseSensorReading(yaw[i-1])
    x_new = parseSensorReading(yaw[i])
    delta = getDelta(x_old, x_new)
    cumSum += delta

注意:我更改了 for 循环中的“范围”表达式,因为它使用列表“偏航”作为其第二个参数。我假设你想说 len(yaw) + 1,所以“i”的值从 1 到 len(yaw)。

【讨论】:

  • 谢谢!然而,我是在逆时针计算象限。
  • 我在最初的问题陈述中可能有错误陈述。对不起。此外,这似乎不受矢量化的影响。我正在尝试找到一些利用 numpy/pandas 矢量操作的方法。
猜你喜欢
  • 2017-05-24
  • 2021-07-28
  • 2013-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-19
  • 2019-12-21
相关资源
最近更新 更多