Элегантный (самый эффективный) способ проверить, попадает ли угол в круговой доверительный интервал - PullRequest
5 голосов
/ 26 июня 2019

У меня есть следующий образец набора данных:

In [222]: df
Out[222]:
    ci_low  circ_time_angle  ci_high
0       30               30       30
1       10                0       20
2     -188              143      207
3     -188                4      207
4     -188                8      207
5     -188               14      207
6     -188              327      207
7      242               57      474
8      242              283      474
9      242                4      474
10    -190              200       -1
11     -90              300        0
12     -25               15       60
13     -30              349      350
14     420               30      600
15    -100               23      719
16    -100               23      259
17    -350                5      -10
18    -350               11      -10

где:

  • ci_low - это нижняя граница кругового доверительного интервала (CI)
  • circ_time_angle - это угол, который я хочу проверить, попадает ли он в CI или нет
  • ci_high - это верхняя граница кругового доверительного интервала (CI)

Ограничения:

  • 0 <= circ_time_angle <= 360
  • ci_high >= ci_low
  • ci_low и ci_high do NOT обязательно принадлежит [0, 360] (см. Строки [2-18] в образце набора данных).

Вопрос: каков будет элегантный способпроверьте, попадает ли угол circ_time_angle в круговой доверительный интервал: [ci_low, ci_high]?Или мне нужно отдельно проверить все крайние случаи?

Желаемый / результирующий набор данных:

In [224]: res
Out[224]:
    ci_low  circ_time_angle  ci_high  falls_into_CI
0       30               30       30           True
1       10                0       20          False
2     -188              143      207           True
3     -188                4      207           True
4     -188                8      207           True
5     -188               14      207           True
6     -188              327      207           True
7      242               57      474           True
8      242              283      474           True
9      242                4      474           True
10    -190              200       -1           True
11     -90              300        0           True
12     -25               15       60           True
13     -30              349      350           True
14     420               30      600          False
15    -100               23      719           True
16    -100               23      259           True
17    -350                5      -10          False
18    -350               11      -10           True

Я также пытался преобразовать границы CI в [0, 360] идо [-180, 180], но это все равно не помогло мне найти элегантную формулу.


Пример настройки набора данных:

data = {
'ci_low': [30,
  10,
  -188,
  -188,
  -188,
  -188,
  -188,
  242,
  242,
  242,
  -190,
  -90,
  -25,
  -30,
  420,
  -100,
  -100,
  -350,
  -350],
 'circ_time_angle': [30,
  0,
  143,
  4,
  8,
  14,
  327,
  57,
  283,
  4,
  200,
  300,
  15,
  349,
  30,
  23,
  23,
  5,
  11],
 'ci_high': [30,
  20,
  207,
  207,
  207,
  207,
  207,
  474,
  474,
  474,
  -1,
  0,
  60,
  350,
  600,
  719,
  259,
  -10,
  -10]}
  
df = pd.DataFrame(data)

Ответы [ 2 ]

1 голос
/ 26 июня 2019

Я бы попытался нормализовать ci_low в диапазоне [0: 360) и изменить ci_high на то же значение.Тогда я бы добавил 360 к circ_time_angle, если он ниже ci_low.

. После этого условие быть внутри интервала CI просто circ_time_angle<ci_high.

. Я использовал вспомогательныйфрейм данных для предотвращения каких-либо изменений в df:

limits = df[['ci_low', 'ci_high']].copy()   # copy ci_low and ci_high
limits.columns=['low', 'high']              # rename to have shorter names
# ensure ci_low is in the [0-360) range
delta = (limits['low'] // 360) * 360
limits['low'] -= delta
limits['high'] -= delta
limits['circ'] = df['circ_time_angle']      # copy circ_time_angle
# add 360 to circ_time_angle if it is below low
limits.loc[limits.circ < limits.low, 'circ'] += 360
df['falls_into_CI'] = limits['circ']<=limits['high']

Это дает ожидаемый результат:

    ci_low  circ_time_angle  ci_high  falls_into_CI
0       30               30       30           True
1       10                0       20          False
2     -188              143      207           True
3     -188                4      207           True
4     -188                8      207           True
5     -188               14      207           True
6     -188              327      207           True
7      242               57      474           True
8      242              283      474           True
9      242                4      474           True
10    -190              200       -1           True
11     -90              300        0           True
12     -25               15       60           True
13     -30              349      350           True
14     420               30      600          False
15    -100               23      719           True
16    -100               23      259           True
17    -350                5      -10          False
18    -350               11      -10           True

Приятный момент, если все векторизовано.

1 голос
/ 26 июня 2019

В настоящее время у меня возникла следующая идея:

  1. проверить эти интервалы CI, охватывающие 360+ градусов, и установить результат в True для соответствующих строк
  2. для всех остальных рядов поверните все углы (столбцы: ['ci_low', 'circ_time_angle', 'ci_high']) так, чтобы ci_low == 0 и сравни повернул circ_time_angle % 360 <= ci_high % 360

Код:

def angle_falls_into_interval(angle, lower, upper, high=360):
    # rotate ALL angles in the way, 
    # so that the lower angle = 0 degrees / radians.
    lower = np.asarray(lower)
    angle = np.asarray(angle) - lower
    upper = np.asarray(upper) - lower
    lower -= lower
    return np.where(upper-lower >= high, 
                    True, 
                    (angle % high) <= (upper % high))

Проверка:

In [232]: res = df.assign(falls_into_CI=angle_falls_into_interval(df.circ_time_angle, 
                                                                  df.ci_low, 
                                                                  df.ci_high,
                                                                  high=360))

In [233]: res
Out[233]:
    ci_low  circ_time_angle  ci_high  falls_into_CI
0       30               30       30           True
1       10                0       20          False
2     -188              143      207           True
3     -188                4      207           True
4     -188                8      207           True
5     -188               14      207           True
6     -188              327      207           True
7      242               57      474           True
8      242              283      474           True
9      242                4      474           True
10    -190              200       -1           True
11     -90              300        0           True
12     -25               15       60           True
13     -30              349      350           True
14     420               30      600          False
15    -100               23      719           True
16    -100               23      259           True
17    -350                5      -10          False
18    -350               11      -10           True
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...