Учитывая данные, как показано ниже, вот что я хочу: внутри только строк, содержащих самую раннюю дату для каждого серийного номера, найдите строки, где Location равен нулю, и обновите их указанным значением по умолчанию.
df = pd.DataFrame([['123456',pd.to_datetime('1/1/2019'),'Location A'],
['123456',pd.to_datetime('1/2/2019'),np.nan],
['123456',pd.to_datetime('1/3/2019'),np.nan],
['123456',pd.to_datetime('5/1/2019'),np.nan],
['654321',pd.to_datetime('2/1/2019'),'Location B'],
['654321',pd.to_datetime('2/2/2019'),'Location B'],
['654321',pd.to_datetime('2/3/2019'),'Location C'],
['112233',pd.to_datetime('3/1/2019'),np.nan],
['112233',pd.to_datetime('3/2/2019'),'Location D'],
['112233',pd.to_datetime('3/3/2019'),np.nan],
['445566',pd.to_datetime('4/1/2019'),'Location E'],
['445566',pd.to_datetime('4/2/2019'),'Location E'],
['445566',pd.to_datetime('4/3/2019'),'Location E'],
['778899',pd.to_datetime('5/1/2019'),np.nan],
['778899',pd.to_datetime('5/2/2019'),np.nan],
['778899',pd.to_datetime('5/3/2019'),np.nan],
['332211',pd.to_datetime('6/1/2019'),np.nan],
['332211',pd.to_datetime('6/2/2019'),'Location F'],
['332211',pd.to_datetime('6/3/2019'),'Location F'],
['665544',pd.to_datetime('7/1/2019'),'Location G'],
['665544',pd.to_datetime('7/2/2019'),'Location G'],
['665544',pd.to_datetime('7/3/2019'),'Location G'],
['998877',pd.to_datetime('8/1/2019'),'Location H'],
['998877',pd.to_datetime('8/2/2019'),'Location I'],
['998877',pd.to_datetime('8/2/2019'),'Location I'],
['147258',pd.to_datetime('9/1/2019'),np.nan],
['147258',pd.to_datetime('9/2/2019'),np.nan],
['147258',pd.to_datetime('9/3/2019'),'Location J']],
columns=['Serial','Date','Location'])
df
Out[498]:
Serial Date Location
0 123456 2019-01-01 Location A
1 123456 2019-01-02 NaN
2 123456 2019-01-03 NaN
3 123456 2019-05-01 NaN
4 654321 2019-02-01 Location B
5 654321 2019-02-02 Location B
6 654321 2019-02-03 Location C
7 112233 2019-03-01 NaN
8 112233 2019-03-02 Location D
9 112233 2019-03-03 NaN
10 445566 2019-04-01 Location E
11 445566 2019-04-02 Location E
12 445566 2019-04-03 Location E
13 778899 2019-05-01 NaN
14 778899 2019-05-02 NaN
15 778899 2019-05-03 NaN
16 332211 2019-06-01 NaN
17 332211 2019-06-02 Location F
18 332211 2019-06-03 Location F
19 665544 2019-07-01 Location G
20 665544 2019-07-02 Location G
21 665544 2019-07-03 Location G
22 998877 2019-08-01 Location H
23 998877 2019-08-02 Location I
24 998877 2019-08-02 Location I
25 147258 2019-09-01 NaN
26 147258 2019-09-02 NaN
27 147258 2019-09-03 Location J
Таким образом, в приведенном выше примере должны быть выбраны только строки 6, 12, 15 и 24. У меня это работает со следующей строкой, которая:
- Использует groupby для получения списка индексов минимальных дат
- Сравнивает это с индексом df, возвращает логическую серию
- Проверяет наличие любых нулей в столбце Location, возвращает еще один логический ряд
- Сравнивает два логических ряда, возвращает окончательный логический ряд
- Наконец, выбирает записи Location на основе этой последней логической серии
В то время как функциональный, это чувствует себя неуклюжим и окольным. Есть ли лучший способ?
df.loc[pd.Series(df.index).isin(df.groupby('Serial')['Date'].idxmin().tolist()) & df['Location'].isnull(), 'Location'] = 'XXXX'
df
Out[502]:
Serial Date Location
0 123456 2019-01-01 Location A
1 123456 2019-01-02 NaN
2 123456 2019-01-03 NaN
3 123456 2019-05-01 NaN
4 654321 2019-02-01 Location B
5 654321 2019-02-02 Location B
6 654321 2019-02-03 Location C
7 112233 2019-03-01 XXXX
8 112233 2019-03-02 Location D
9 112233 2019-03-03 NaN
10 445566 2019-04-01 Location E
11 445566 2019-04-02 Location E
12 445566 2019-04-03 Location E
13 778899 2019-05-01 XXXX
14 778899 2019-05-02 NaN
15 778899 2019-05-03 NaN
16 332211 2019-06-01 XXXX
17 332211 2019-06-02 Location F
18 332211 2019-06-03 Location F
19 665544 2019-07-01 Location G
20 665544 2019-07-02 Location G
21 665544 2019-07-03 Location G
22 998877 2019-08-01 Location H
23 998877 2019-08-02 Location I
24 998877 2019-08-02 Location I
25 147258 2019-09-01 XXXX
26 147258 2019-09-02 NaN
27 147258 2019-09-03 Location J
РЕДАКТИРОВАТЬ: Добавлена новая строка 3 в образец df, чтобы прояснить, что даты уникальны в группах серийных номеров, но не могут быть уникальными среди серийных номеров. Строка с индексом 3 в этом примере имеет ту же дату, что и минимальная дата другого сериала, но ее не следует выбирать. Я справился с этим, сопоставив индексы вместо самих дат, но то, как я это сделал, кажется грязным.