Счётчик в столбце по ненулевым данным с учётом значений в ещё одном столбце
Есть посуточные показания датчиков. Необходимо задать счётчик ненулевых значений по датчикам и по количеству показаний, т.е. от первого ненулевого значения до нуля - 1; от следующего ненулевого значения до нуля -2; при этом для нового датчика счётчик должен начаться снова с 1.
Пример фрейма данных (англ. DataFrame):
import pandas as pd
d={
'Дата':['01.01.2020','02.01.2020','03.01.2020','04.01.2020','05.01.2020','01.01.2020','02.01.2020','03.01.2020','04.01.2020','05.01.2020'],
'Датчик':[1,1,1,1,1,1,2,2,2,2],
'Показания':[0,2,3,5,0,22,3,0,11,22]
}
df= pd.DataFrame(data=d)
Вид таблицы:
Желаемый результат:
Вот этот пример, который ближе всего к моему вопросу, но я не до конца понимаю как его преобразовать, чтобы получить нужный результат.
Объединил оба примера в один и в результате получил нужный счётчик:
df = pd.DataFrame({
'Дата': ['01.01.2020','02.01.2020','03.01.2020','04.01.2020','05.01.2020','01.01.2020','02.01.2020','03.01.2020','04.01.2020','05.01.2020','06.02.2021','07.02.2021','08.02.2021','09.02.2021','10.02.2021','11.02.2021'],
'Датчик': [1,1,1,1,1,1,2,2,2,2,3,3,3,3,3,3],
'Показания': [0,2,3,5,0,22,3,0,11,22,0,0,37,8,0,95] })
grp1=df[~df['Показания'].isin([0])]
grp = grp1.groupby("Датчик")["Показания"]
first_idxs = grp.apply(lambda x: x.index[0])
df["счетчик"] = np.where(
df["Показания"] != 0,
df.groupby("Датчик")["Показания"].apply(lambda x: ((x.shift().eq(0) & x.ne(0))| (x.ne(0)&(x.index.isin(first_idxs))) ).cumsum()),
0
)
df
Дата Датчик Показания счетчик
0 01.01.2020 1 0 0
1 02.01.2020 1 2 1
2 03.01.2020 1 3 1
3 04.01.2020 1 5 1
4 05.01.2020 1 0 0
5 01.01.2020 1 22 2
6 02.01.2020 2 3 1
7 03.01.2020 2 0 0
8 04.01.2020 2 11 2
9 05.01.2020 2 22 2
10 06.02.2021 3 0 0
11 07.02.2021 3 0 0
12 08.02.2021 3 37 1
13 09.02.2021 3 8 1
14 10.02.2021 3 0 0
15 11.02.2021 3 95 2
Может кто-нибудь более подробно объяснить что происходит в строчке
grp = grp1.groupby("Датчик")["Показания"]
При группировке по "Датчик" параметру "Показания" присваивается индекс первого встречного значения?
В этой строчке:
df.groupby("Датчик")["Показания"].apply(lambda x: ((x.shift().eq(0) & x.ne(0))| (x.ne(0)&(x.index.isin(first_idxs))) ).cumsum())
Функция lambda возвращает x если условие сработало и затем считается их количество? apply нужно чтобы применить функцию lambda к каждому датчику отдельно? интуитивно вроде понятно, но все же...
Ответы (2 шт):
Если я правильно понял вопрос:
grp = df.groupby("Датчик")["Показания"]
first_idxs = grp.apply(lambda x: x.index[0])
df["счетчик"] = np.where(
df["Показания"] != 0,
grp.apply(lambda x: (x.index.isin(first_idxs) | x.eq(0)).cumsum()),
0
)
результат:
In [71]: df
Out[71]:
Дата Датчик Показания счетчик
0 01.01.2020 1 0 0
1 02.01.2020 1 2 1
2 03.01.2020 1 3 1
3 04.01.2020 1 5 1
4 05.01.2020 1 0 0
5 01.01.2020 1 22 2
6 02.01.2020 2 3 1
7 03.01.2020 2 0 0
8 04.01.2020 2 11 2
9 05.01.2020 2 22 2
Вариант ответа для измененных входных данных:
d = {
'Дата':['01.01.2020','02.01.2020','03.01.2020','04.01.2020','05.01.2020','01.01.2020','02.01.2020','03.01.2020','04.01.2020','05.01.2020'],
'Датчик':[1,1,1,1,1,1,2,2,2,2],
'Показания':[0,2,3,5,0,22,0,0,11,22]
}
df= pd.DataFrame(data=d)
решение:
df["счетчик"] = \
df.groupby("Датчик")["Показания"].apply(lambda x: (x.shift().eq(0) & x.ne(0)).cumsum())
результат:
In [110]: df
Out[110]:
Дата Датчик Показания счетчик
0 01.01.2020 1 0 0
1 02.01.2020 1 2 1
2 03.01.2020 1 3 1
3 04.01.2020 1 5 1
4 05.01.2020 1 0 1
5 01.01.2020 1 22 2
6 02.01.2020 2 0 0
7 03.01.2020 2 0 0
8 04.01.2020 2 11 1
9 05.01.2020 2 22 1
df["счетчик"] = np.where(
df["Показания"] != 0,
df.groupby("Датчик")["Показания"].apply(lambda x: (x.shift().eq(0) & x.ne(0)).cumsum()),
0
)
In [156]: df
Out[156]:
Дата Датчик Показания счетчик
0 01.01.2020 1 0 0
1 02.01.2020 1 2 1
2 03.01.2020 1 3 1
3 04.01.2020 1 5 1
4 05.01.2020 1 0 0
5 01.01.2020 1 22 2
6 02.01.2020 2 3 0
7 03.01.2020 2 0 0
8 04.01.2020 2 11 1
9 05.01.2020 2 22 1
10 06.02.2021 3 0 0
11 07.02.2021 3 0 0
12 08.02.2021 3 37 1
13 09.02.2021 3 8 1
14 10.02.2021 3 0 0
15 11.02.2021 3 95 2

