#python #pandas #pandas-groupby
#питон #pandas #pandas-groupby
Вопрос:
Я новичок в методах groupby в Pandas и, похоже, не могу разобраться в этом. У меня есть данные с ~ 2 млн записей, и выполнение моего текущего кода займет 4 дня — из-за неэффективного использования ‘append’.
Я анализирую данные с производства с помощью 2 флагов для указания проблем с тестовыми образцами. Для первых нескольких флагов из каждого Test_ID должно быть установлено значение False.(Причина: недостаточно данных для точного анализа этих первых нескольких из каждой группы)
Моя неэффективная попытка (правильный результат, но недостаточно быстрый для 2-х строк):
df = pd.DataFrame({'Test_ID' : ['foo', 'foo', 'foo', 'foo',
'bar', 'bar', 'bar'],
'TEST_Date' : ['2020-01-09 09:49:31',
'2020-01-09 12:16:15',
'2020-01-09 12:47:44',
'2020-01-09 14:39:05',
'2020-01-09 17:39:47',
'2020-01-09 20:44:58',
'2020-01-10 18:40:47'],
'Flag1' : [True, False, True, False, True, False, False],
'Flag2' : [True, False, False, False, True, False, False],
})
#generate a list of Test_IDs
Test_IDs = list(df['Test_ID'].unique())
#generate a list of columns in the dataframe
cols = list(df)
#generate a new dataframe with the same columns as the original
df_output = pd.DataFrame(columns = cols)
for i in Test_IDs:
#split the data into groups, iterate over each group
df_2 = df[df['Test_ID'] == i].copy()
#set the first two rows of Flag1 to False for each group
df_2.iloc[:2, df_2.columns.get_loc('Flag1')] = 0
#set the first three rows of Flag2 to False for each group
df_2.iloc[:3, df_2.columns.get_loc('Flag2')] = 0
df_output = df_output.append(df_2) #add the latest group onto the output df
print(df_output)
Ввод:
Flag1 Flag2 TEST_Date Test_ID
0 True True 2020-01-09 09:49:31 foo
1 False False 2020-01-09 12:16:15 foo
2 True False 2020-01-09 12:47:44 foo
3 False False 2020-01-09 14:39:05 foo
4 True True 2020-01-09 17:39:47 bar
5 False False 2020-01-09 20:44:58 bar
6 False False 2020-01-10 18:40:47 bar
Выходной сигнал:
Flag1 Flag2 TEST_Date Test_ID
0 False False 2020-01-09 09:49:31 foo
1 False False 2020-01-09 12:16:15 foo
2 True False 2020-01-09 12:47:44 foo
3 False False 2020-01-09 14:39:05 foo
4 False False 2020-01-09 17:39:47 bar
5 False False 2020-01-09 20:44:58 bar
6 False False 2020-01-10 18:40:47 bar
Ответ №1:
Давайте сделаем groupby().cumcount()
:
# enumeration of rows within each `Test_ID`
enum = df.groupby('Test_ID').cumcount()
# overwrite the Flags
df.loc[enum < 2, 'Flag1'] = False
df.loc[enum < 3, 'Flag2'] = False
Вывод:
Test_ID TEST_Date Flag1 Flag2
0 foo 2020-01-09 09:49:31 False False
1 foo 2020-01-09 12:16:15 False False
2 foo 2020-01-09 12:47:44 True False
3 foo 2020-01-09 14:39:05 False False
4 bar 2020-01-09 17:39:47 False False
5 bar 2020-01-09 20:44:58 False False
6 bar 2020-01-10 18:40:47 False False
Комментарии:
1. простой и элегантный ответ.
2. Я думаю, что OP имеет разные пороговые значения для двух флагов. Необходимо разделить их, но это очень элегантное решение.
3. @itaishz спасибо, что указали на это. Ответ обновлен.
4. @QuangHoang Первоначальные результаты по частичному набору данных улучшили время с 60 секунд до 0,45 секунды… Будет обновляться после завершения полного набора данных (30 минут для загрузки). Приветствуется!