Существует ли более эффективный способ обработки фактов, которые дублируются в кадре данных R?

#r #dataframe #duplicates #hierarchical-data

Вопрос:

У меня есть фрейм данных, который выглядит так:

 ID <- c(1,1,1,2,2,2,2,3,3,3,3)
Fact <- c(233,233,233,50,50,50,50,15,15,15,15)
Overall_Category <- c("Purchaser","Purchaser","Purchaser","Car","Car","Car","Car","Car","Car","Car","Car")
Descriptor <- c("Country", "Gender", "Eyes", "Color", "Financed", "Type", "Transmission", "Color", "Financed", "Type", "Transmission")
Members <- c("America", "Male", "Brown", "Red", "Yes", "Sedan", "Manual", "Blue","No", "Van", "Automatic")

df <- data.frame(ID, Fact, Overall_Category, Descriptor, Members)
 

Измерения фреймов данных работают следующим образом:

  • Всегда будет существовать идентификатор/ключ, который однозначно и однозначно идентифицирует представленный факт
  • Для данного факта всегда будет существовать измерение, определяющее общую категорию, к которой принадлежит представленный факт.
  • В большинстве случаев — но не всегда — для «Дескриптора»будет существовать измерение,
  • Если для данного факта существует измерение «Дескриптор», будет другое измерение «Члены», чтобы показать возможные члены в «Дескрипторе».

Проблема заключается в том, что один представленный факт дублируется для данного идентификатора на основе того, сколько измерений применяется к данному факту. То, что я хотел бы, — это способ показать факт только один раз, основываясь на его идентификаторе, и сохранить применимые измерения для этого одного идентификатора.

Я достиг этого, сделав это:

 df1 <- pivot_wider(df, 
id_cols = ID,
names_from = c(Overall_Category, Descriptor, Members),
names_prefix = "zzzz",
values_from = Fact,
names_sep = "-",
names_repair = "unique")

ColumnNames <- df1 %>% select(matches("zzzz")) %>% colnames()


df2 <- df1 %>% mutate(mean_sel = rowMeans(select(., ColumnNames), na.rm = T))
df3 <- df2 %>% mutate_at(ColumnNames, function(x) ifelse(!is.na(x), deparse(substitute(x)), NA))
df3 <- df3 %>% unite('Descriptor', ColumnNames, na.rm = T, sep = "_")
df3 <- df3 %>% mutate_at("Descriptor", str_replace_all, "zzzz", "")
 

Но, похоже, что это не будет хорошо масштабироваться для фактов со многими измерениями из-за pivot_wide, и в целом не кажется очень эффективным подходом.

Есть ли лучший способ сделать это?

Ответ №1:

Вы можете unite объединить столбцы и для каждого ID из них и взять среднее Fact значение.

 library(dplyr)
library(tidyr)

df %>%
  unite(Descriptor, Overall_Category:Members, sep = '-', na.rm = TRUE) %>%
  group_by(ID) %>%
  summarise(Descriptor = paste0(Descriptor, collapse = '_'), 
            mean_sel = mean(Fact, na.rm = TRUE))

#     ID Descriptor                                               mean_sel
#  <dbl> <chr>                                                       <dbl>
#1     1 Purchaser-Country-America_Purchaser-Gender-Male_Purchas…      233
#2     2 Car-Color-Red_Car-Financed-Yes_Car-Type-Sedan_Car-Trans…       50
#3     3 Car-Color-Blue_Car-Financed-No_Car-Type-Van_Car-Transmi…       15
 

Ответ №2:

Я думаю, вам нужны простые paste sep аргументы и collapse аргументы

 library(dplyr, warn.conflicts = F)

df %>% group_by(ID, Fact) %>%
  summarise(Descriptor = paste(paste(Overall_Category, Descriptor, Members, sep = '-'), collapse = '_'), .groups = 'drop')

# A tibble: 3 x 3
     ID  Fact Descriptor                                                            
  <dbl> <dbl> <chr>                                                                 
1     1   233 Purchaser-Country-America_Purchaser-Gender-Male_Purchaser-Eyes-Brown  
2     2    50 Car-Color-Red_Car-Financed-Yes_Car-Type-Sedan_Car-Transmission-Manual 
3     3    15 Car-Color-Blue_Car-Financed-No_Car-Type-Van_Car-Transmission-Automatic
 

Ответ №3:

Вариант с str_c

 library(dplyr)
library(stringr)
df %>%
   group_by(ID, Fact) %>%
   summarise(Descriptor = str_c(Overall_Category, Descriptor, Members, sep= "-", collapse="_"), .groups = 'drop')