tidy: создать ключ без rowwise()?

#r #dplyr #key #tibble #rowwise

#r #dplyr #Клавиша #tibble #rowwise

Вопрос:

Есть ли способ создать key без использования rowwise() ?

Любой указатель очень ценится.

 df <- tibble(grp1=rev(LETTERS[1:5]),grp2=letters[11:15],grp3=LETTERS[1:5],
      value=rnorm(5,10,10))

df %>% rowwise %>% mutate(key=paste(sort(c(grp1, grp2)), collapse="")) %>% ungroup()
  
   grp1  grp2  grp3  value             key  
  <chr> <chr> <chr> <chr>             <chr>
1 E     k     A     -3.73984194875213 AE   
2 D     l     B     3.25846392371014  BD   
3 C     m     C     3.62405652088127  CC   
4 B     n     D     6.41520621902784  BD   
5 A     o     E     20.1892413026407  AE 
  

Обновление: tibble содержит несколько символьных векторов, но key должен быть сгенерирован из столбца grp1 и grp3 .

Ответ №1:

используя purrr::pmap_chr :

 library(tidyverse)
df %>% mutate(key=pmap_chr(.[c("grp1","grp3")],~paste(sort(c(...)), collapse="")))
# # A tibble: 5 x 5
#   grp1  grp2  grp3  value             key  
#   <chr> <chr> <chr> <chr>             <chr>
# 1 E     k     A     22.0150932758833  AE   
# 2 D     l     B     2.24725610156698  BD   
# 3 C     m     C     -6.2414882455089  CC   
# 4 B     n     D     22.5699168856552  BD   
# 5 A     o     E     -6.21443670571301 AE 
  

В базе R вы могли бы сделать:

 transform(df, key=mapply(function(...) paste(sort(c(...)), collapse=""), grp1, grp3)
  

Комментарии:

1. Спасибо за ваш ответ! Я обновил свой вопрос… Может ли это сработать, когда у вас есть несколько символьных векторов / столбцов и вам нужно указать, из какого сгенерировать ключ?

2. Пожалуйста, избегайте изменения вопросов таким образом, чтобы ответы устарели, лучше обновить дополнительным примером

3. Прошу прощения за оплошность. Да, ваш ответ решает проблему. Большое спасибо, очень аккуратно!

4. Спасибо @Moody_Mudskipper за обновление обоих ответов. Как оказалось, ответ @AntoniosK быстрее для моих реальных данных (оценивается с помощью profvis::profvis() )

5. На df <- as_tibble(cbind(grp1=sample(size=1000,x=rev(LETTERS[1:5]),replace=T),grp2=sample(size=1000,x=letters[11:15],replace=T),grp3=sample(size=1000,x=LETTERS[1:5],replace=T),value=rnorm(1000,10,10))) аккуратный подход Moody_Mudskipper занимает 30 мс, а аккуратный подход AntoniosK — 10 мс.

Ответ №2:

Вот векторная опция с использованием pmin/pmap . Возьмите min/max для каждой строки столбцов ‘grp1’, ‘grp3’ с pmin/pmax и объедините вместе ( str_c )

 library(dplyr)
library(stringr)
df %>%
   mutate(key = str_c(pmin(grp1, grp3), pmax(grp1, grp3)))
# A tibble: 5 x 5
#  grp1  grp2  grp3   value key  
#  <chr> <chr> <chr>  <dbl> <chr>
#1 E     k     A      24.7  AE   
#2 D     l     B       5.66 BD   
#3 C     m     C      16.3  CC   
#4 B     n     D       5.88 BD   
#5 A     o     E      -9.22 AE   
  

данные

 df <- tibble(grp1=rev(LETTERS[1:5]),grp2=letters[11:15],grp3=LETTERS[1:5],
          value=rnorm(5,10,10))
  

ПРИМЕЧАНИЕ: cbind преобразуется в matrix и matrix может содержать только один класс. Преобразование в tibble с as_tibble помощью не изменяет класс автоматически. Вместо этого используйте tibble/data.frame напрямую вместо cbind маршрута

Комментарии:

1. Потрясающе, это невероятно быстро! Спасибо!

Ответ №3:

Другой способ — использовать mutate без rowwise , но с векторизованной версией вашей функции, например, так:

 library(dplyr)

# create a function and vectorise it
f = function(x, y) paste(sort(c(x, y)), collapse="")
f = Vectorize(f)

# use the function
df %>% mutate(key = f(grp1, grp3))

# # A tibble: 5 x 5
#   grp1  grp2  grp3  value             key  
#   <chr> <chr> <chr> <chr>             <chr>
# 1 E     k     A     -4.41213449814982 AE   
# 2 D     l     B     10.4314736952111  BD   
# 3 C     m     C     5.69345098226371  CC   
# 4 B     n     D     4.39266020802413  BD   
# 5 A     o     E     22.0623810028979  AE
  

Комментарии:

1. Спасибо! Очень аккуратно!

2. @AntoniosK: отредактировано, чтобы сделать совместимым с обновленным вопросом