#python #pandas
#python #pandas
Вопрос:
У меня есть фрейм данных, df
, с одним столбцом, extension
.
Значения в extension
столбце циклически увеличиваются и уменьшаются, как показано ниже:
extension
0.000
0.050
0.100
0.150
0.130
0.080
0.020
0.050
0.075
Я пытаюсь обозначить каждый увеличивающийся и уменьшающийся цикл, как показано ниже:
extension lablel
0.000 1
0.050 1
0.100 1
0.150 1
0.130 1
0.080 1
0.020 1
0.050 2
0.075 2
Я немного застрял и был бы признателен за некоторые рекомендации здесь.
Ответ №1:
df['lablel']=df.extension.diff()#Find the difference between consecutive ros in the column extension
df['lablel']=(df.lablel.ge(0)amp;df.lablel.shift(1).le(0)|df.lablel.ge(0)amp;df.lablel.shift(-1).le(0)).cumsum() 1#Find zero crossing from the consecutive differences, cummulatively sum and add 1 to the outcome
extension lablel
0 0.000 1
1 0.050 1
2 0.100 1
3 0.150 2
4 0.130 2
5 0.080 2
6 0.020 2
7 0.050 3
8 0.075 3
Комментарии:
1. Большое спасибо за ваш ответ!! вы мне очень помогли. но еще один быстрый вопрос. Как насчет того, хочу ли я пометить весь цикл, когда? Я имею в виду, что вместо того, чтобы помечать каждое увеличение и уменьшение в столбце расширения, помечайте набор увеличений и уменьшений как один цикл. например, расширение начинается с 0, увеличивается до 0.1 и возвращается к 0.05. Как можно обозначить все это как один цикл?
2. Не уверен, что я вас понял. Отредактируйте свой вопрос и включите пример вывода. Дайте мне знать, как только это будет сделано, и поможет
3. Давайте попробуем
df['lablel']=df.extension.diff()
, а затемdf['lablel']=(df.lablel.ge(0)amp;df.lablel.shift(1).le(0)).cumsum() 1
4. Это помогает, рад помочь дальше
Ответ №2:
Итак, давайте воспроизведем ваши данные:
a = [0.000,0.050,0.100,0.150,0.130,0.080,0.020,0.050,0.075]
df = pd.DataFrame(a, columns=["extension"])
Короткий ответ таков:
df["label"] = pd.Series(np.where(df["extension"].diff() < 0, 0, 1)).diff().abs().cumsum() 1
df.at[0,"label"] = 1
По крайней мере, это мой ответ. Но это определенно выглядит немного неуклюже. Итак, давайте разберем это шаг за шагом для понимания:
df["extension"].diff()
diff
создает разницу между каждой ячейкой и предыдущей. Поэтому он не может вычислить его для первого элемента.
Вывод:
0 NaN
1 0.050
2 0.050
3 0.050
4 -0.020
5 -0.050
6 -0.060
7 0.030
8 0.025
Теперь давайте бинаризуем результат, чтобы обнаружить изменения в положительной / отрицательной разнице, используя where
from numpy:
np.where(df["extension"].diff() < 0, 0, 1)
Вывод:
array([1, 1, 1, 1, 0, 0, 0, 1, 1])
Это говорит нам, является ли разница с предыдущей отрицательной (—> 0) или положительной (—> 1)
Тогда вы хотите знать, только когда меняется положительная / отрицательная тенденция. Поэтому мы включаем diff
функцию еще раз. Предварительно мы должны преобразовать массив numpy обратно в pd.Series
:
pd.Series(np.where(df["extension"].diff() < 0, 0, 1)).diff()
Вывод:
0 NaN
1 0.0
2 0.0
3 0.0
4 -1.0
5 0.0
6 0.0
7 1.0
8 0.0
В конечном счете, вас не интересует, в каком направлении изменился тренд, только то, что он изменился, поэтому мы удаляем эту информацию с abs
помощью функции. А затем суммируйте результат с cumsum
помощью функции, чтобы он мог увеличиваться при каждом изменении:
pd.Series(np.where(df["extension"].diff() < 0, 0, 1)).diff().abs().cumsum()
Вывод:
0 NaN
1 0.0
2 0.0
3 0.0
4 1.0
5 1.0
6 1.0
7 2.0
8 2.0
Наконец, два дополнения, чтобы основать метку на 1, а не на 0, и заменить первый элемент, который был NaN:
1 за кодом и df.at[0,"label"] = 1
И вот что вы делаете:
extension label
0 0.000 1.0
1 0.050 1.0
2 0.100 1.0
3 0.150 1.0
4 0.130 2.0
5 0.080 2.0
6 0.020 2.0
7 0.050 3.0
8 0.075 3.0
РЕДАКТИРОВАТЬ: ответ на отредактированный вопрос в комментариях
Комментарии:
1. Большое вам спасибо за ваше подробное объяснение. Я просто немного отредактировал вопрос, не могли бы вы быстро взглянуть на него?
2. Математически ваш первый запрос был проще, потому что технически это были бы точки перегиба математического графика. Однако, придерживаясь текущего подхода, мы могли бы сказать, что технически вам нужна только половина частоты увеличения метки. Это можно сделать с помощью простого
/ 2
, а затем стереть половинные числа с помощью np.floor:df["label"] = np.floor(pd.Series(np.where(df["extension"].diff() < 0, 0, 1)).diff().abs().cumsum() / 2) 1
и затемdf.at[0,"label"] = 1
3. Спасибо за ваше время и помощь. Я использовал предложение @wwnde, и оно работает. Но спасибо за вашу помощь!