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 / 79493723
Accepted
lovestacksflow
lovestacksflow
Asked: 2025-03-08 09:09:35 +0800 CST2025-03-08 09:09:35 +0800 CST 2025-03-08 09:09:35 +0800 CST

Comparando os valores de um certo número de linhas anteriores com a linha atual

  • 772

Em um banco de dados contendo valores de classe de empresa e patente, quero calcular as seguintes variáveis:

Abandono tecnológico: Número de classes de patentes tecnológicas anteriormente ativas abandonadas anualmente.

Especificamente, quero criar variáveis ​​que calculem o número de classes de patentes (variável = classe) que a empresa usou nos últimos 3 anos (t-3, t-2 e t-1) (a observação mínima de um ano anterior é aceitável se o histórico inicial da empresa não tiver 3 anos), mas que estão faltando neste ano (t). Gostaria de fazer o mesmo com uma janela de 5 anos também.

Tenho um conjunto de dados contendo milhões de linhas, então uma solução rápida de data.table é muito preferível.

No seguinte conjunto de dados:

df <- data.table(year=c(1979,1979,1980,1980,1981,1981,1982,1983,1983,1984,1984),
                 category = c("A","A","B","C","A","D","F","F","C","A","B"))

O resultado desejado seria (para uma janela de três anos):

    year        class tech_aband_3
 1: 1979        A     0
 2: 1979        A     0
 3: 1980        B     1
 4: 1980        C     1
 5: 1981        A     2
 6: 1981        D     2
 7: 1982        F     4
 8: 1983        F     3
 9: 1983        C     3
10: 1984        A     3
11: 1984        B     3

No final, terei que executar a solução pelo ID da empresa.

Muito obrigado antecipadamente.

  • 3 3 respostas
  • 162 Views

3 respostas

  • Voted
  1. Best Answer
    Iroha
    2025-03-08T13:54:45+08:002025-03-08T13:54:45+08:00

    Supondo que todos os anos estejam representados nos dados (caso contrário, você precisará preencher os anos ausentes para que o seguinte funcione), você pode tentar:

    library(data.table)  
      
    df[, .(category = list(unique(category))), by = year
       ][, tech_aband_3 := lengths(mapply(\(x, y) setdiff(unlist(x), y), 
                                          transpose(shift(list(category), 1:3, fill = first(category[[1]]))), 
                                          category))
         ][, .(category = unlist(category)), by = .(year, tech_aband_3)
           ][ df, on = .(year, category)
           ]
    
         year tech_aband_3 category
        <num>        <int>   <char>
     1:  1979            0        A
     2:  1979            0        A
     3:  1980            1        B
     4:  1980            1        C
     5:  1981            2        A
     6:  1981            2        D
     7:  1982            4        F
     8:  1983            3        F
     9:  1983            3        C
    10:  1984            3        A
    11:  1984            3        B
    
    • 5
  2. FJCC
    2025-03-08T12:23:45+08:002025-03-08T12:23:45+08:00

    Aqui está um método que funciona com seus dados de exemplo. Não posso dizer o quão rápido ele será com um grande conjunto de dados.

    library(data.table)
    library(purrr)
    df <- data.table(year=c(1979,1979,1980,1980,1981,1981,1982,1983,1983,1984,1984),
                     category = c("A","A","B","C","A","D","F","F","C","A","B"))
    
    GetCount <- function(CurrYear) {
      Prev <- unique(df[(CurrYear - year) <= 3 & (CurrYear - year) > 0, "category"])
      Current <- unique(df[year == CurrYear, "category"])
      return(nrow(Prev[!Current, on = "category"]))
    }
    
    YEARS <- unique(df$year)       
    COUNTS <- map_dbl(YEARS, GetCount)
    YearsCounts <- data.table(year = YEARS, tech_aband_3 = COUNTS)
    
    FINAL <- YearsCounts[df, on = "year"]
    FINAL
    
         year tech_aband_3 category
        <num>        <num>   <char>
     1:  1979            0        A
     2:  1979            0        A
     3:  1980            1        B
     4:  1980            1        C
     5:  1981            2        A
     6:  1981            2        D
     7:  1982            4        F
     8:  1983            3        F
     9:  1983            3        C
    10:  1984            3        A
    11:  1984            3        B
    
    • 3
  3. 2025-03-08T21:24:29+08:002025-03-08T21:24:29+08:00

    Aqui está uma comparação incluindo uma abordagem RCCP.

    library(data.table)
    library(purrr)
    
    set.seed(1)
    dat <- data.table(year=seq(1:3000),category = sample(LETTERS, 3000, replace = TRUE))
    
    calc_tech_abandonment1 <- function(dt, window) {  
      return(dt[, paste0("tech_aband_", window) := {
        past_categories <- unique(dt[year %between% c(.BY$year - window, .BY$year - 1), category])
        current_category <- unique(dt[year == .BY$year, category])
        length(setdiff(past_categories, current_category)) # Calculate the number of abandoned categories
      }, by = year])
    }
    
    calc_tech_abandonment2 <- function(dt, window){ 
      GetCount <- function(CurrYear) {
        Prev <- unique(dt[(CurrYear - year) <= window & (CurrYear - year) > 0, "category"])
        Current <- unique(dt[year == CurrYear, "category"])
        return(nrow(Prev[!Current, on = "category"]))
      }  
      YEARS <- unique(dt$year)       
      COUNTS <- map_dbl(YEARS, GetCount)
      YearsCounts <- data.table(year = YEARS, tech_aband_3 = COUNTS)
      return(YearsCounts[dt, on = "year"][, .(year, category, tech_aband_3)])
      
    }
    
    calc_tech_abandonment3 <- function(dt) {
      return(dt[, .(category = list(unique(category))), by = year
      ][, tech_aband_3 := lengths(mapply(\(x, y) setdiff(unlist(x), y), 
                                         transpose(shift(list(category), 1:3, fill = first(category[[1]]))), 
                                         category))
      ][, .(category = unlist(category)), by = .(year, tech_aband_3)
      ][ dt, on = .(year, category)][, .(year, category, tech_aband_3)])
    }
    
    ## RCPP
    Rcpp::cppFunction('
    IntegerVector calc_tech_abandonment_cpp(DataFrame dt, int window) {
      IntegerVector years = dt["year"];
      CharacterVector categories = dt["category"];
      
      std::unordered_map<int, std::unordered_set<std::string>> year_to_categories;
      for (int i = 0; i < years.size(); i++) {
        year_to_categories[years[i]].insert(std::string(categories[i]));
      }
      
      IntegerVector result(years.size());
      for (int i = 0; i < years.size(); i++) {
        int current_year = years[i];
        std::unordered_set<std::string> past_categories;
        
        for (int j = 1; j <= window; j++) {
          int past_year = current_year - j;
          if (year_to_categories.count(past_year)) {
            past_categories.insert(year_to_categories[past_year].begin(), year_to_categories[past_year].end());
          }
        }
        
        std::unordered_set<std::string> current_categories = year_to_categories[current_year];
        int abandoned_count = 0;
        for (const auto& cat : past_categories) {
          if (current_categories.find(cat) == current_categories.end()) {
            abandoned_count++;
          }
        }
        
        result[i] = abandoned_count;
      }
      
      return result;
    }')
    
    calc_tech_abandonment_rcpp <- function(dt, window) {
      return(dt[, paste0("tech_aband_", window) := calc_tech_abandonment_cpp(dt, window)])
    }
    
    # Benchmark
    
    bench <- microbenchmark::microbenchmark(
      calc_tech_abandonment1 = calc_tech_abandonment1(dat, window = 3),
      calc_tech_abandonment2 = calc_tech_abandonment2(dat, window = 3), 
      calc_tech_abandonment3 = calc_tech_abandonment3(dat),
      calc_tech_abandonment_rcpp = calc_tech_abandonment_rcpp(dat, 3),
      times = 10
    )
    

    Resultados

    Unit: milliseconds
                           expr       min        lq       mean     median        uq       max neval cld
         calc_tech_abandonment1 4413.0690 4513.0162 4551.91333 4568.17215 4593.8609 4609.8427    10 a  
         calc_tech_abandonment2 6247.0388 6323.6385 6405.84832 6377.23535 6496.3481 6563.5206    10  b 
         calc_tech_abandonment3   57.2013   59.5997   63.21687   61.88805   66.1977   76.8084    10   c
     calc_tech_abandonment_rcpp    2.0205    2.1013    2.33757    2.14720    2.1735    4.2637    10   c
    
    • -1

relate perguntas

  • Adicionar número de série para atividade de cópia ao blob

  • A fonte dinâmica do empacotador duplica artefatos

  • Selecione linhas por grupo com 1s consecutivos

  • Lista de chamada de API de gráfico subscritoSkus estados Privilégios insuficientes enquanto os privilégios são concedidos

  • Função para criar DFs separados com base no valor da coluna

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