Определите среднее значение «данных», где максимальное число CONTINUOUS cond = True

У меня есть панда Dataframe с столбцом «data» и «cond» (- ition). Мне нужно среднее значение (столбца данных) строк с наибольшим количеством объектов CONTINUOUS True в 'cond'.

Example DataFrame: cond data 0 True 0.20 1 False 0.30 2 True 0.90 3 True 1.20 4 True 2.30 5 False 0.75 6 True 0.80 Result = 1.466, which is the mean value of row-indexes 2:4 with 3 True 

Я не смог найти «векторизованное» решение с помощью метода groupby или pivot. Поэтому я написал func, который петли строки. К сожалению, это занимает около часа на 1 миллион линий, что является долгой. К сожалению, украшение @jit не уменьшает длительность измеряемой величины.

Данные, которые я хочу проанализировать, – это проект мониторинга в течение одного года, и у меня есть каждые 3 часа DataFrame с одним миллионом строк. Таким образом, около 3000 таких файлов.

Эффективное решение будет очень важным. Я также очень благодарен за решение в numpy.

2 Solutions collect form web for “Определите среднее значение «данных», где максимальное число CONTINUOUS cond = True”

Вот основанный на NumPy подход –

 # Extract the relevant cond column as a 1D NumPy array and pad with False at # either ends, as later on we would try to find the start (rising edge) # and stop (falling edge) for each interval of True values arr = np.concatenate(([False],df.cond.values,[False])) # Determine the rising and falling edges as start and stop start = np.nonzero(arr[1:] > arr[:-1])[0] stop = np.nonzero(arr[1:] < arr[:-1])[0] # Get the interval lengths and determine the largest interval ID maxID = (stop - start).argmax() # With maxID get max interval range and thus get mean on the second col out = df.data.iloc[start[maxID]:stop[maxID]].mean() 

Тест времени выполнения

Подходы как функции –

 def pandas_based(df): # @ayhan's soln res = df['data'].groupby((df['cond'] != df['cond'].shift()).\ cumsum()).agg(['count', 'mean']) return res[res['count'] == res['count'].max()] def numpy_based(df): arr = np.concatenate(([False],df.cond.values,[False])) start = np.nonzero(arr[1:] > arr[:-1])[0] stop = np.nonzero(arr[1:] < arr[:-1])[0] maxID = (stop - start).argmax() return df.data.iloc[start[maxID]:stop[maxID]].mean() 

Сроки –

 In [208]: # Setup dataframe ...: N = 1000 # Datasize ...: df = pd.DataFrame(np.random.rand(N),columns=['data']) ...: df['cond'] = np.random.rand(N)>0.3 # To have 70% True values ...: In [209]: %timeit pandas_based(df) 100 loops, best of 3: 2.61 ms per loop In [210]: %timeit numpy_based(df) 1000 loops, best of 3: 215 µs per loop In [211]: # Setup dataframe ...: N = 10000 # Datasize ...: df = pd.DataFrame(np.random.rand(N),columns=['data']) ...: df['cond'] = np.random.rand(N)>0.3 # To have 70% True values ...: In [212]: %timeit pandas_based(df) 100 loops, best of 3: 4.12 ms per loop In [213]: %timeit numpy_based(df) 1000 loops, best of 3: 331 µs per loop 

Используя подход из расчета числа конкретных последовательных равных значений в векторном виде в пандах :

 df['data'].groupby((df['cond'] != df['cond'].shift()).cumsum()).agg(['count', 'mean'])[lambda x: x['count']==x['count'].max()] Out: count mean cond 3 3 1.466667 

Для индексирования по вызываемому требуется 0.18.0, для более ранних версий вы можете:

 res = df['data'].groupby((df['cond'] != df['cond'].shift()).cumsum()).agg(['count', 'mean']) res[res['count'] == res['count'].max()] Out: count mean cond 3 3 1.466667 

Как это работает:

Первая часть, df['cond'] != df['cond'].shift() возвращает булевский массив:

 df['cond'] != df['cond'].shift() Out: 0 True 1 True 2 True 3 False 4 False 5 True 6 True Name: cond, dtype: bool 

Поэтому значение равно False, если строка такая же, как и выше. Это означает, что если вы возьмете кумулятивную сумму, эти строки (последовательные) будут иметь одинаковое число:

 (df['cond'] != df['cond'].shift()).cumsum() Out: 0 1 1 2 2 3 3 3 4 3 5 4 6 5 Name: cond, dtype: int32 

Поскольку groupby принимает любую группу для группировки (нет необходимости передавать столбец, вы можете передать произвольный список), это можно использовать для группировки результатов. .agg(['count', 'mean'] часть просто дает соответствующие подсчеты и средства для каждой группы, и в конце она выбирает ту, которая имеет наибольший счет.

Обратите внимание, что это также сгруппировало бы последовательные False. Если вы хотите рассматривать только последовательные True, вы можете изменить группу группировки на:

 ((df['cond'] != df['cond'].shift()) | (df['cond'] != True)).cumsum() 

Поскольку мы хотим, чтобы False, когда условие True, условие стало «не равно строке ниже ИЛИ не True». Таким образом, исходная строка изменится на:

 df['data'].groupby(((df['cond'] != df['cond'].shift()) | (df['cond'] != True)).cumsum()).agg(['count', 'mean'])[lambda x: x['count']==x['count'].max()] 
  • Почему для импорта функции из модуля требуется больше времени, чем весь модуль?
  • Хранение объектов Python в списке Python по сравнению с массивом Numpy с фиксированной длиной
  • Свяжите ATLAS / MKL с установленным Numpy
  • numpy на многоядерном оборудовании
  • Почему numpy медленнее, чем для цикла
  • Python: почему * и ** быстрее, чем / и sqrt ()?
  • Фильтрация панд или массивов numpy для непрерывных рядов с минимальной длиной окна
  • Производительность создания нового DataFrame
  • Ускорьте Pandas cummin / cummax
  • Разница между производительностью или стилем между «if» и «if not»?
  • различия в производительности при работе в Linux и Windows
  • Python - лучший язык программирования в мире.