1

I have a data frame like this that want to apply diff function on:

test = pd.DataFrame({ 'Observation' : ['0','1','2',
                         '3','4','5',
                         '6','7','8'],
                  'Value' : [30,60,170,-170,-130,-60,-30,10,20]
            })

Observation Value
0   30
1   60
2   170
3   -170
4   -130
5   -60
6   -30
7   10
8   20

The column 'Value' is in degrees. So, the difference between -170 and 170 should be 20, not -340. In other words, when d2*d1 < 0, instead of d2-d1, I'd like to get 360-(abs(d1)+abs(d2))

Here's why I try. But then I don't know how to continue it without using a for loop:

test['Value_diff_1st_attempt'] = test['Value'].diff(1)
test['sign_temp'] = test['Value'].shift()
test['Sign'] = np.sign(test['Value']*test['sign_temp'])

Here's what the result should look like:

Observation Value Delta_Value
0   30   NAN    
1   60   30 
2   170    110
3   -170   20   
4   -130   40
5   -60    70
6   -30   30
7   10   40
8   20   10

Eventually I'd like to get just the magnitude of differences all in positive values. Thanks.

Update: So, the value results are derived from math.atan2 function. The values are from 0<theta<180 or -180<theta<0. The problem arises when we are dealing with a change of direction from 170 (upper left corner) to -170 (lower left corner) for example, where the change is really just 20 degrees. However, when we go from -30 (Lower right corner) to 10 (upper right corner), the change is really 40 degrees. I hope I explained it well.

4

1 回答 1

2

I believe this should work (took the definition from @JasonD's answer):

test["Value"].rolling(2).apply(lambda x: 180 - abs(abs(x[0] - x[1]) - 180))
Out[45]: 
0      NaN
1     30.0
2    110.0
3     20.0
4     40.0
5     70.0
6     30.0
7     40.0
8     10.0
Name: Value, dtype: float64

How it works:

Based on your question, the two angles a and b are between 0 and +/-180. For 0 < d < 180 I will write d < 180 and for -180 < d < 0 I will write d < 0. There are four possibilities:

  • a < 180, b < 180 -> the result is simply |a - b|. And since |a - b| - 180 cannot be greater than 180, the formula will simplify to a - b if a > b and b - a if b > a.
  • a < 0, b < 0 - > The same logic applies here. Both negative and their absolute difference cannot be greater than 180. The result will be |a - b|.
  • a < 180, b < 0 - > a - b will be greater than 0 for sure. For the cases where |a - b| > 180, we should look at the other angle and this translates to 360 - |a - b|.
  • a < 0, b < 180 -> again, similar to the above. If the absolute difference is greater than 180, calculate 360 - absolute difference.

For the pandas part: rolling(n) creates arrays of size n. For 2: (row 0, row1), (row1, row2), ... With apply, you apply that formula to every rolling pair where x[0] is the first element (a) and x[1] is the second element.

于 2016-05-09T18:35:45.387 回答