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 / 77754517
Accepted
jpsmith
jpsmith
Asked: 2024-01-04 04:32:58 +0800 CST2024-01-04 04:32:58 +0800 CST 2024-01-04 04:32:58 +0800 CST

Usando pivot_longer para múltiplas colunas desarrumadas

  • 772

Eu tenho estes dados (desorganizados) contendo a fase do regime medicamentoso de cada paciente (ip ou cp), o nome do medicamento (codificado como um número) e informações sobre a dose para vários medicamentos:

df_have

#   id ip_drug1 ip_dose1 ip_drug2 ip_dose2 cp_drug1 cp_dose1 cp_drug2 cp_dose2
# 1 A1        1      300        3      100        6      500        7      100
# 2 A2        1      300        2      200       11      300       NA       NA
# 3 A3        1      500       NA       NA        9      100        5     1500

Gostaria de deixar esses dados organizados e em formato longo:

df_want

#    id phase drug dose
# 1  A1    ip    1  300
# 2  A1    ip    3  100
# 3  A1    cp    6  500
# 4  A1    cp    7  100
# 5  A2    ip    1  300
# 6  A2    ip    2  200
# 7  A2    cp   11  300
# 8  A2    cp   NA   NA
# 9  A3    ip    1  500
# 10 A3    ip   NA   NA
# 11 A3    cp    9  100
# 12 A3    cp    5 1500

Consegui obter o quadro de dados desejado com uma combinação de tidyr::pivot_longer,, dplyr::mutatee tidyr::pivot_wider(e dplyr::select):

library(tidyr)
library(dplyr)

df_have %>% 
  pivot_longer(cols = -id, 
               names_to = c("phase", "type"),
               names_pattern = "(cp|ip)_(drug|dose)") %>%
  mutate(temp = row_number(), 
         .by = c(id, phase, type)) %>%
  pivot_wider(names_from = type, 
              values_from = value) %>%
  select(-temp)

No entanto, o código de várias etapas acima é muito lento em meus dados reais muito grandes. Eu gostaria de realizar essa transformação mais rapidamente em tidyr/ dplyr, de preferência em uma única pivot_wideretapa. Isso é possível?


Quadros reproduzíveis df_havee df_wantde dados:

# have
df_have <- data.frame(id = paste0("A", 1:3), 
                 ip_drug1 = 1,
                 ip_dose1 = c(300, 300, 500),
                 ip_drug2 = c(3, 2, NA),
                 ip_dose2 = c(100, 200, NA),
                 cp_drug1 = c(6, 11, 9),
                 cp_dose1 = c(500, 300, 100),
                 cp_drug2 = c(7, NA, 5),
                 cp_dose2 = c(100, NA, 1500))

# want
df_want <- data.frame(id = rep(paste0("A", 1:3), each = 4),
                      phase = rep(rep(c("ip", "cp"), each = 2), times = 3),
                      drug = c(1, 3, 6, 7, 1, 2, 11, NA, 1, NA, 9, 5),
                      dose = c(300, 100, 500, 100, 300, 200, 300, NA, 500, NA, 100, 1500))
  • 2 2 respostas
  • 96 Views

2 respostas

  • Voted
  1. Best Answer
    LMc
    2024-01-04T04:52:01+08:002024-01-04T04:52:01+08:00

    É possível em uma única pivot_longeretapa. Isso deve ser cerca de 4,5x mais rápido:

    library(tidyr)
    
    df_have |>
      pivot_longer(-id,
                   names_pattern = "(.*?)_(.*?)\\d",
                   names_to = c("phase", ".value")) 
    

    Acho que a chave é o uso de .valueno names_toargumento. De ?pivot_longer:

    ".value" indica que o componente correspondente do nome da coluna define o nome da coluna de saída que contém os valores das células, substituindo values_tototalmente.

    Referência

    A solução de @ThomasIsCoding é ainda mais rápida (~ 12x)

    one_pivot <- function() {
      df_have |>
        pivot_longer(-id,
                     names_pattern = "(.*?)_(.*?)\\d",
                     names_to = c("phase", ".value"))
    }
    
    current <- function() {
      df_have %>% 
        pivot_longer(cols = -id, 
                     names_to = c("phase", "type"),
                     names_pattern = "(cp|ip)_(drug|dose)") %>%
        mutate(temp = row_number(), 
               .by = c(id, phase, type)) %>%
        pivot_wider(names_from = type, 
                    values_from = value) %>%
        select(-temp)
    }
    
    base <- function() {
      out <- reshape(
        setNames(
          df_have,
          gsub("(\\D+)_(\\D+)", "\\2_\\1", names(df_have))
        ),
        direction = "long",
        idvar = "id",
        varying = -1,
        sep = "_",
        timevar = "phase"
      )
      
      transform(
        `row.names<-`(out[order(out$id), ], NULL),
        phase = sub("\\d+$", "", phase)
      )
    }
    
    bench::mark(
      current(),
      one_pivot(),
      base(),
      relative = TRUE,
      check = FALSE
    )
      
      expression    min median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time result memory               time       gc      
      <bch:expr>  <dbl>  <dbl>     <dbl>     <dbl>    <dbl> <int> <dbl>   <bch:tm> <list> <list>               <list>     <list>  
    1 current()   11.4   11.4       1          Inf     1.04    27     2      463ms <NULL> <Rprofmem [141 × 3]> <bench_tm> <tibble>
    2 one_pivot()  2.54   2.67      4.43       Inf     1      124     2      480ms <NULL> <Rprofmem [22 × 3]>  <bench_tm> <tibble>
    3 base()       1      1        11.7        NaN     1.52   322     3      473ms <NULL> <Rprofmem [0 × 3]>   <bench_tm> <tibble>
    

    Saída

       id    phase  drug  dose
       <chr> <chr> <dbl> <dbl>
     1 A1    ip        1   300
     2 A1    ip        3   100
     3 A1    cp        6   500
     4 A1    cp        7   100
     5 A2    ip        1   300
     6 A2    ip        2   200
     7 A2    cp       11   300
     8 A2    cp       NA    NA
     9 A3    ip        1   500
    10 A3    ip       NA    NA
    11 A3    cp        9   100
    12 A3    cp        5  1500
    
    • 6
  2. ThomasIsCoding
    2024-01-04T06:00:55+08:002024-01-04T06:00:55+08:00

    Aqui está uma solução base R com um únicoreshape

    out <- reshape(
        setNames(
            df_have,
            gsub("(\\D+)_(\\D+)", "\\2_\\1", names(df_have))
        ),
        direction = "long",
        idvar = "id",
        varying = -1,
        sep = "_",
        timevar = "phase"
    )
    
    df_want <- transform(
        `row.names<-`(out[order(out$id), ], NULL),
        phase = sub("\\d+$", "", phase)
    )
    

    que dá

    > df_want
       id phase drug dose
    1  A1    ip    1  300
    2  A1    ip    3  100
    3  A1    cp    6  500
    4  A1    cp    7  100
    5  A2    ip    1  300
    6  A2    ip    2  200
    7  A2    cp   11  300
    8  A2    cp   NA   NA
    9  A3    ip    1  500
    10 A3    ip   NA   NA
    11 A3    cp    9  100
    12 A3    cp    5 1500
    
    • 5

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

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

    • 1 respostas
  • Marko Smith

    Por que esse código Java simples e pequeno roda 30x mais rápido em todas as JVMs Graal, mas não em nenhuma JVM Oracle?

    • 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

    Quando devo usar um std::inplace_vector em vez de um std::vector?

    • 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
  • Marko Smith

    Estou tentando fazer o jogo pacman usando apenas o módulo Turtle Random e Math

    • 1 respostas
  • Martin Hope
    Aleksandr Dubinsky Por que a correspondência de padrões com o switch no InetAddress falha com 'não cobre todos os valores de entrada possíveis'? 2024-12-23 06:56:21 +0800 CST
  • Martin Hope
    Phillip Borge Por que esse código Java simples e pequeno roda 30x mais rápido em todas as JVMs Graal, mas não em nenhuma JVM Oracle? 2024-12-12 20:46:46 +0800 CST
  • Martin Hope
    Oodini Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores? 2024-12-12 06:27:11 +0800 CST
  • Martin Hope
    sleeptightAnsiC `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso? 2024-11-09 07:18:53 +0800 CST
  • Martin Hope
    The Mad Gamer Quando devo usar um std::inplace_vector em vez de um std::vector? 2024-10-29 23:01:00 +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
  • Martin Hope
    MarkB Por que o GCC gera código que executa condicionalmente uma implementação SIMD? 2024-02-17 06:17:14 +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