需要使用R将数据框安排为汇总数据框

时间:2020-04-10 11:29:35

标签: r dataframe dplyr

我正在R中使用以下数据框。

dput:

structure(list(uid = c("K-1", "K-1", 
"K-2", "K-3", "K-4", "K-5", 
"K-6", "K-7", "K-8", "K-9", 
"K-10", "K-11", "K-12", "K-13", 
"K-14"), Date = c("2020-03-16 12:11:33", "2020-03-16 12:11:33", 
"2020-03-16 06:13:55", "2020-03-16 10:03:43", "2020-03-16 12:37:09", 
"2020-03-16 06:40:24", "2020-03-16 09:46:45", "2020-03-16 12:07:44", 
"2020-03-16 14:09:51", "2020-03-16 09:19:23", "2020-03-16 09:07:37", 
"2020-03-16 11:48:34", "2020-03-16 06:23:24", "2020-03-16 04:39:03", 
"2020-03-16 04:59:13"), batch_no = c(7, 7, 8, 9, 9, 8, 
7, 6, 7, 9, 8, 8, 7, 7, 7), marking = c("S1", "S1", "S2", 
"SE_hold1", "SD_hold1", "SD_hold2", "S3", "S3", "", "SA_hold3", "S1", "S1", "S2", 
"S3", "S3"), seq = c("FRD", 
"FHL", NA, NA, NA, NA, NA, NA, "ABC", NA, NA, NA, NA, "DEF", NA)), .Names = c("uid", 
"Date", "batch_no", "marking",
"seq"), row.names = c(NA, 15L), class = "data.frame")






uid     Date                  batch_no       marking       seq
K-1     16/03/2020  12:11:33  7              S1            FRD
K-1     16/03/2020  12:11:33  7              S1            FHL
K-2     16/03/2020  12:11:33  8              SE_hold1      ABC
K-3     16/03/2020  12:11:33  9              SD_hold2      DEF
K-4     16/03/2020  12:11:33  8              S1            XYZ
K-5     16/03/2020  12:11:33                 NA            ABC
K-6     16/03/2020  12:11:33  7                            ZZZ
K-7     16/03/2020  12:11:33  NA             S2            NA
K-8     16/03/2020  12:11:33  6              S3            FRD
  • seq列将具有包括NA在内的八个唯一值,并非所有8个值都可用于每天的日期。
  • batch_no将有六个唯一值,包括NA和空白,这不是所有六个值都可用于每天的日期。
  • marking列将具有〜25个唯一值,但需要将带有后缀_hold#的值视为Hold,之后将有六个唯一值,包括空白和NA

要求是按以下顺序合并dcast数据框,以具有用于分析的单个视图摘要。

我想在代码中将所有唯一值保持静态,这样,如果特定值在特定日期不可用,我将在汇总表中得到0或-。

所需的输出:

seq      count  percentage   Marking     count     Percentage     batch_no   count    Percentage
FRD      1      12.50%       S1          2         25.00%         6          1        12.50%
FHL      1      12.50%       S2          1         12.50%         7          2        25.00%
ABC      2      25.00%       S3          1         12.50%         8          2        25.00%
DEF      1      12.50%       Hold        2         25.00%         9          1        12.50%
XYZ      1      12.50%       NA          1         12.50%         NA         1        12.50%
ZZZ      1      12.50%       (Blank)     1         12.50%         (Blank)    1        12.50%
FRD      1      12.50%         -         -           -             -         -           -
NA       1      12.50%         -         -           -             -         -           -
(Blank)  0      0.00%          -         -           -             -         -           -
Total    8      112.50%        -         8         100.00%         -         8         100.00%

对于seq,我们有%> 100,因为对值uidFRD重复计算了相同的FHL。那是公认的情况。在Total中将只有uid个不同的计数。

我正在使用SO的下述代码,但无法获得所需的输出。

df = df_original %>% 
  mutate(marking = if_else(str_detect(marking,"hold"),"Hold", marking)) %>% 
  mutate_at(vars(c("seq", "batch_no", "marking")), forcats::fct_explicit_na, na_level = "(Blank)") 

## You Need to do something similar with vectors of the possible values
df_combinations = purrr::cross_df(list(seq = df$seq %>% unique(),
                     batch_no = df$batch_no %>% unique(),
                     marking = df$marking %>% unique()))

df_all_combination = df_combinations %>% 
  left_join(df, by = c("seq", "batch_no", "marking")) %>% 
  group_by(seq, batch_no, marking) %>% 
  summarise(count = n())

1 个答案:

答案 0 :(得分:2)

Base R解决方案(请注意:我不确定我是否完全理解您的问题):

  # Function to summarise each of the vectors required: summariser => function
summariser <- function(vec) {
  within(unique(data.frame(
    vec = vec,
    counter = as.numeric(ifelse(is.na(vec), sum(is.na(vec)),
                     ave(vec, vec, FUN = length))), stringsAsFactors = FALSE
  )),
  {
    perc = paste0(round(counter / sum(counter) * 100, 2), "%")
  })
}
# Vectors to summarise: vecs_to_summarise => character vector
vecs_to_summarise <- c("seq", "marking", "batch_no")

# Create an empty list in order to allocate some memory: df_list => list
df_list <- vector("list", length(vecs_to_summarise))

# Apply the summariser function to each of the vectors required: df_list => list of dfs
df_list <- lapply(df[,vecs_to_summarise], summariser)

# Rename the vectors of each data.frame in the list: df_list => list of dfs: 
df_list <- lapply(seq_along(df_list), function(i) {
  names(df_list[[i]]) <- gsub("_vec", "",
                              paste(names(df_list[i]), names(df_list[[i]]), sep = "_"))
  return(df_list[[i]])
})


# Determine the number of rows of the maximum data.frame: numeric scalar 
max_df_length <- max(sapply(df_list, nrow))

# Extend each data.frame to be the same length (pad with NAs if necessary): df_list => list
df_list <- lapply(seq_along(df_list), function(i){
  y <- data.frame(df_list[[i]][rep(seq_len(nrow(df_list[[1]])), each = 1),])
  y[1:(nrow(y)),] <- NA
  y <- y[1:(max_df_length - nrow(df_list[[i]])),]
  if(length(y) > 0){
    x <- data.frame(rbind(df_list[[i]], y)[1:max_df_length,])
  }else{
      x <- data.frame(df_list[[i]][1:max_df_length,])
      }
  return(x)
  }
)

# Bind the data.frames in the list into a single df: analysed_df => data.frame
analysed_df <- do.call("cbind", df_list)

数据:

df <- structure(list(uid = c("K-1", "K-1", "K-2", "K-3", "K-4", "K-5", 
    "K-6", "K-7", "K-8"), Date = structure(c(1584321093, 1584321093, 
    1584321093, 1584321093, 1584321093, 1584321093, 1584321093, 1584321093, 
    1584321093), class = c("POSIXct", "POSIXt"), tzone = ""), batch_no = c(7L, 
    7L, 8L, 9L, 8L, NA, 7L, NA, 6L), marking = c("S1", "S1", "SE_hold1", 
    "SD_hold2", "S1", NA, NA, "S2", "S3"), seq = c("FRD", "FHL", 
    "ABC", "DEF", "XYZ", "ABC", "ZZZ", NA, "FRD")), row.names = c(NA, 
    -9L), class = "data.frame")