Eu tenho um dataframe pandas que se parece com
data = {
'Date': ['2024-07-14','2024-07-14','2024-07-14','2024-07-14','2024-07-14','2024-03-14','2024-03-14','2024-03-14','2024-02-14','2024-02-10','2024-02-10','2024-02-10','2024-04-13','2024-04-13','2023-02-11','2023-02-11','2023-02-11','2011-10-11','2011-05-02','2011-05-02'],
'Test_Number': [5,4,3,2,1,3,2,1,4,3,2,1,2,1,3,2,1,1,2,1],
'Student_ID': [2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1],
'Place': [3,5,7,3,1,9,6,3,7,8,2,1,3,4,2,1,5,6,2,7]
}
df = pd.DataFrame(data)
e eu gostaria de criar três novas colunas 'student_rec_1', 'student_rec_2', 'student_rec_3' usando o seguinte método:
para cada Student_ID, student_rec_1 é igual à posição desse aluno no último teste na data mais próxima e é igual a np.nan se não existir.
Da mesma forma, student_rec_2 é igual à posição desse aluno no segundo último teste na data mais próxima e é igual a np.nan se não existir.
student_rec_3 é igual ao lugar daquele aluno no terceiro último teste na última data mais próxima, e é igual a np.nan se não existir. Então o resultado desejado parece
data_new = {
'Date': ['2024-07-14','2024-07-14','2024-07-14','2024-07-14','2024-07-14','2024-03-14','2024-03-14','2024-03-14','2024-02-14','2024-02-10','2024-02-10','2024-02-10','2024-04-13','2024-04-13','2023-02-11','2023-02-11','2023-02-11','2011-10-11','2011-05-02','2011-05-02'],
'Test_Number': [5,4,3,2,1,3,2,1,4,3,2,1,2,1,3,2,1,1,2,1],
'Student_ID': [2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1],
'Place': [3,5,7,3,1,9,6,3,7,8,2,1,3,4,2,1,5,6,2,7],
'student_rec_1': [9,9,9,9,9,7,7,7,8,np.nan,np.nan,np.nan,2,2,6,6,6,2,np.nan,np.nan],
'student_rec_2': [6,6,6,6,6,8,8,8,2,np.nan,np.nan,np.nan,1,1,2,2,2,7,np.nan,np.nan],
'student_rec_3': [3,3,3,3,3,2,2,2,1,np.nan,np.nan,np.nan,5,5,7,7,7,np.nan,np.nan,np.nan]
}
df_new = pd.DataFrame(data_new)
Foi isso que eu tentei:
df['Data'] = pd.to_datetime(df['Data'])
df = df.sort_values(['Data', 'Número_do_Teste'], ascendente=[Falso, Falso])
def get_last_n_records(grupo, n): retornar grupo['Lugar'].shift(-n)
df['student_rec_1'] = df.groupby('ID_do_aluno').apply(obter_últimos_n_registros, 1).reset_index(nível=0, descartar=Verdadeiro) df['student_rec_2'] = df.groupby('ID_do_aluno').apply(obter_últimos_n_registros, 2).reset_index(nível=0, descartar=Verdadeiro) df['student_rec_3'] = df.groupby('ID_do_aluno').apply(obter_últimos_n_registros, 3).reset_index(nível=0, descartar=Verdadeiro)
mas isso apenas mudou o lugar de cada aluno e não levou em conta o aspecto do "último dia" e apenas mudaria o lugar independentemente.
Primeiro converta a coluna
Date
porto_datetime
, crie um auxiliarDataFrame
com colunas de renomeaçãodf_cand
para que seja possível usar a junção esquerda para o original (para evitar remover o índice original é usadorename
). Em seguida, filtre por data e hora, classificando e crie um contador porGroupBy.cumcount
para obter3
os últimos valores, que são mesclados ao originaldf
:EDIT: Para melhor desempenho é possível usar a solução trabalhando por grupos com numpy - comparar datas para todos os anteriores a
mask
, criar ordem por soma cumulativa pornumpy.cumsum
, então é possível obterN
a ordenação superior comnumpy.argmax
. Porque é possível que alguns valores não existam é necessário adicionar condição comnumpy.any
e retornar colunas necessárias: