У меня есть фрейм данных с датой и временем и столбцом. Мне нужно найти максимальное растяжение нулевых значений в «конкретной дате» и заменить его нулем. В приведенном ниже примере 1 января максимальное растягивающее нулевое значение равно 3 раза, поэтому я должен заменить этот ноль. Точно так же я должен повторить процесс для 2 января.
Примечание. Только максимальное количество нулевых значений должно быть заменено нулем, а не остальными.
Ниже приведены мои образцы данных:
Datetime X
01-01-2018 00:00 1
01-01-2018 00:05 Nan
01-01-2018 00:10 2
01-01-2018 00:15 3
01-01-2018 00:20 2
01-01-2018 00:25 Nan
01-01-2018 00:30 Nan
01-01-2018 00:35 Nan
01-01-2018 00:40 4
02-01-2018 00:00 Nan
02-01-2018 00:05 2
02-01-2018 00:10 2
02-01-2018 00:15 2
02-01-2018 00:20 2
02-01-2018 00:25 Nan
02-01-2018 00:30 Nan
02-01-2018 00:35 3
02-01-2018 00:40 Nan






Использовать:
#convert columns to floats and datetimes
df['X'] = df['X'].astype(float)
df['Datetime'] = pd.to_datetime(df['Datetime'], dayfirst=True)
#check missing values
s = df['X'].isna()
#create consecutive groups
g = s.ne(s.shift()).cumsum()
#get dates from datetimes
dates = df['Datetime'].dt.date
#get counts of consecutive NaNs
sizes = s.groupby([g[s], dates[s]]).transform('count')
#compare max count per dates to mask
mask = sizes.groupby(dates).transform('max').eq(sizes)
#set 0 by mask
df.loc[mask, 'X'] = 0
print (df)
Datetime X
0 2018-01-01 00:00:00 1.0
1 2018-01-01 00:05:00 NaN
2 2018-01-01 00:10:00 2.0
3 2018-01-01 00:15:00 3.0
4 2018-01-01 00:20:00 2.0
5 2018-01-01 00:25:00 0.0
6 2018-01-01 00:30:00 0.0
7 2018-01-01 00:35:00 0.0
8 2018-01-01 00:40:00 4.0
9 2018-01-02 00:00:00 NaN
10 2018-01-02 00:05:00 2.0
11 2018-01-02 00:10:00 2.0
12 2018-01-02 00:15:00 2.0
13 2018-01-02 00:20:00 2.0
14 2018-01-02 00:25:00 0.0
15 2018-01-02 00:30:00 0.0
16 2018-01-02 00:35:00 3.0
17 2018-01-02 00:40:00 NaN
Обновлено: вы можете создать filtered список всех дат и времени для замены и цепочки вместе с маской для проверки отсутствующих значений с помощью & для побитового И:
sizes = s.groupby([g[s & m], dates[s & m]]).transform('count')
Все вместе:
df['X'] = df['X'].astype(float)
df['Datetime'] = pd.to_datetime(df['Datetime'], dayfirst=True)
#check missing values
s = df['X'].isna()
#create consecutive groups
g = s.ne(s.shift()).cumsum()
#get dates from datetimes
dates = df['Datetime'].dt.floor('d')
filtered = ['2018-01-01','2019-01-01']
m = dates.isin(filtered)
#get counts of consecutive NaNs
sizes = s.groupby([g[s & m], dates[s & m]]).transform('count')
#compare max count per dates to mask
mask = sizes.groupby(dates).transform('max').eq(sizes)
#set 0 by mask
df.loc[mask, 'X'] = 0
print (df)
Datetime X
0 2018-01-01 00:00:00 1.0
1 2018-01-01 00:05:00 NaN
2 2018-01-01 00:10:00 2.0
3 2018-01-01 00:15:00 3.0
4 2018-01-01 00:20:00 2.0
5 2018-01-01 00:25:00 0.0
6 2018-01-01 00:30:00 0.0
7 2018-01-01 00:35:00 0.0
8 2018-01-01 00:40:00 4.0
9 2018-01-02 00:00:00 NaN
10 2018-01-02 00:05:00 2.0
11 2018-01-02 00:10:00 2.0
12 2018-01-02 00:15:00 2.0
13 2018-01-02 00:20:00 2.0
14 2018-01-02 00:25:00 NaN
15 2018-01-02 00:30:00 NaN
16 2018-01-02 00:35:00 3.0
17 2018-01-02 00:40:00 NaN
интересный вопрос.
Мое решение написано на scala, но я уверен, что ему есть эквивалент на python.
Первое - настройки. Я использовал case class KV; в вашем примере ключом будет дата, а значением будет столбец X.
import org.apache.spark.sql.expressions.Window
import org.apache.spark.sql.{functions => F}
case class KV(k: String, v: Double)
val ds = Seq(("a", 0.0),
("a", Double.NaN),
("a", Double.NaN),
("b", Double.NaN),
("b", Double.NaN)).toDF("k", "v").as[KV]
val win = Window.partitionBy("k")
def countConsecutiveNans(s: String, iter: Iterator[KV]): Int = {
(0 /: iter)((cnt: Int, kv: KV) => if (kv.v.isNaN) cnt+1 else 0)
}
ds.groupByKey(kv => kv.k).mapGroups(countConsecutiveNans)
Результирующий набор данных:
+-----+
|value|
+-----+
| 2|
| 2|
+-----+
Надеялся, что это помогло!
Привет Израэль, спасибо за ваш комментарий. Что делать, если у меня есть данные за один год с 5-минутными временными метками, и я хочу применить этот процесс только для нескольких выбранных дат, а не для каждой даты?