AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 79447714
Accepted
Ishigami
Ishigami
Asked: 2025-02-18 17:23:36 +0800 CST2025-02-18 17:23:36 +0800 CST 2025-02-18 17:23:36 +0800 CST

Criando uma nova coluna de acordo com a última data mais próxima no dataframe do Pandas

  • 772

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.

pandas
  • 1 1 respostas
  • 71 Views

1 respostas

  • Voted
  1. Best Answer
    jezrael
    2025-02-18T18:09:51+08:002025-02-18T18:09:51+08:00

    Primeiro converta a coluna Datepor to_datetime, crie um auxiliar DataFramecom colunas de renomeação df_candpara que seja possível usar a junção esquerda para o original (para evitar remover o índice original é usado rename). Em seguida, filtre por data e hora, classificando e crie um contador por GroupBy.cumcountpara obter 3os últimos valores, que são mesclados ao original df:

    df['Date'] = pd.to_datetime(df['Date'])
    
    df = df.reset_index().rename(columns={'index':'orig_index'})
    
    df_cand = (df.rename(columns={'Date':'cand_Date',
                                 'Test_Number':'cand_Test_Number',
                                 'Place':'cand_Place'})
                 .drop(['orig_index'], axis=1))
    
    merged = df.merge(df_cand, on='Student_ID', how='left')
    
    merged = merged[merged['cand_Date'].lt(merged['Date'])]
    merged = merged.sort_values(['Student_ID','orig_index','cand_Date','cand_Test_Number'],
                                 ascending=[True,True,False,False])
    
    merged['cand_rank'] = merged.groupby('orig_index').cumcount().add(1)
    
    pivot = (merged[merged['cand_rank'].le(3)]
              .pivot(index='orig_index',columns='cand_rank',values='cand_Place')
              .add_prefix('student_rec'))
    
    out = df.join(pivot).drop('orig_index', axis=1)
    

    print(out)
    
             Date  Test_Number  Student_ID  Place  student_rec_1  student_rec_2  \
    0  2024-07-14            5           2      3            9.0            6.0   
    1  2024-07-14            4           2      5            9.0            6.0   
    2  2024-07-14            3           2      7            9.0            6.0   
    3  2024-07-14            2           2      3            9.0            6.0   
    4  2024-07-14            1           2      1            9.0            6.0   
    5  2024-03-14            3           2      9            7.0            8.0   
    6  2024-03-14            2           2      6            7.0            8.0   
    7  2024-03-14            1           2      3            7.0            8.0   
    8  2024-02-14            4           2      7            8.0            2.0   
    9  2024-02-10            3           2      8            NaN            NaN   
    10 2024-02-10            2           2      2            NaN            NaN   
    11 2024-02-10            1           2      1            NaN            NaN   
    12 2024-04-13            2           1      3            2.0            1.0   
    13 2024-04-13            1           1      4            2.0            1.0   
    14 2023-02-11            3           1      2            6.0            2.0   
    15 2023-02-11            2           1      1            6.0            2.0   
    16 2023-02-11            1           1      5            6.0            2.0   
    17 2011-10-11            1           1      6            2.0            7.0   
    18 2011-05-02            2           1      2            NaN            NaN   
    19 2011-05-02            1           1      7            NaN            NaN   
    
        student_rec_3  
    0             3.0  
    1             3.0  
    2             3.0  
    3             3.0  
    4             3.0  
    5             2.0  
    6             2.0  
    7             2.0  
    8             1.0  
    9             NaN  
    10            NaN  
    11            NaN  
    12            5.0  
    13            5.0  
    14            7.0  
    15            7.0  
    16            7.0  
    17            NaN  
    18            NaN  
    19            NaN  
    

    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 por numpy.cumsum, então é possível obter Na ordenação superior com numpy.argmax. Porque é possível que alguns valores não existam é necessário adicionar condição com numpy.anye retornar colunas necessárias:

    df['Date'] = pd.to_datetime(df['Date'])
    
    N = 3
    
    def f(x):
    
        dates = x['Date'].to_numpy()        
        places = x['Place'].astype(float).to_numpy() 
    
        mask = dates < dates[:, None]  
        cs = np.cumsum(mask, axis=1) 
        targets = np.array(range(1, N+1))[None, :] 
        cs_ext = cs[..., None]
    
        cond = cs_ext == targets
        first_idx = np.argmax(cond, axis=1)
        m = np.any(cond, axis=1) 
    
        arr = places[first_idx]  
        arr[~m] = np.nan
    
        return pd.DataFrame(arr, 
                            index=x.index, 
                            columns=[f'student_rec_{i+1}' for i in range(N)])
    
    
    out = df.join(df.groupby('Student_ID', group_keys=False)[['Place','Date']].apply(f))
    

    print(out)
             Date  Test_Number  Student_ID  Place  student_rec_1  student_rec_2  \
    0  2024-07-14            5           2      3            9.0            6.0   
    1  2024-07-14            4           2      5            9.0            6.0   
    2  2024-07-14            3           2      7            9.0            6.0   
    3  2024-07-14            2           2      3            9.0            6.0   
    4  2024-07-14            1           2      1            9.0            6.0   
    5  2024-03-14            3           2      9            7.0            8.0   
    6  2024-03-14            2           2      6            7.0            8.0   
    7  2024-03-14            1           2      3            7.0            8.0   
    8  2024-02-14            4           2      7            8.0            2.0   
    9  2024-02-10            3           2      8            NaN            NaN   
    10 2024-02-10            2           2      2            NaN            NaN   
    11 2024-02-10            1           2      1            NaN            NaN   
    12 2024-04-13            2           1      3            2.0            1.0   
    13 2024-04-13            1           1      4            2.0            1.0   
    14 2023-02-11            3           1      2            6.0            2.0   
    15 2023-02-11            2           1      1            6.0            2.0   
    16 2023-02-11            1           1      5            6.0            2.0   
    17 2011-10-11            1           1      6            2.0            7.0   
    18 2011-05-02            2           1      2            NaN            NaN   
    19 2011-05-02            1           1      7            NaN            NaN   
    
        student_rec_3  
    0             3.0  
    1             3.0  
    2             3.0  
    3             3.0  
    4             3.0  
    5             2.0  
    6             2.0  
    7             2.0  
    8             1.0  
    9             NaN  
    10            NaN  
    11            NaN  
    12            5.0  
    13            5.0  
    14            7.0  
    15            7.0  
    16            7.0  
    17            NaN  
    18            NaN  
    19            NaN  
    
    • 3

relate perguntas

  • Extraia a string da linha duplicada, remova a duplicata, forneça a contagem de strings [duplicada]

  • percorrendo colunas para gerar countplot () seaborn

  • Como posso obter o máximo de cada linha em uma coluna de índice

  • Crie uma matriz dask com pyarrow dtype

  • Divida as entradas no dataframe [duplicado]

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Reformatar números, inserindo separadores em posições fixas

    • 6 respostas
  • Marko Smith

    Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não?

    • 2 respostas
  • Marko Smith

    Problema com extensão desinstalada automaticamente do VScode (tema Material)

    • 2 respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Martin Hope
    Fantastic Mr Fox Somente o tipo copiável não é aceito na implementação std::vector do MSVC 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant Encontre o próximo dia da semana usando o cronógrafo 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor O inicializador de membro do construtor pode incluir a inicialização de outro membro? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul O C++20 mudou para permitir a conversão de `type(&)[N]` de matriz de limites conhecidos para `type(&)[]` de matriz de limites desconhecidos? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann Como/por que {2,3,10} e {x,3,10} com x=2 são ordenados de forma diferente? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve