簡體   English   中英

R:循環瀏覽列表以比較列名並在數據框中創建新字段

[英]R: Loop through list to compare column names and create new fields in data frame

我使用jsonlite平了json數據,並添加了一些奇異的列名。 請參閱下面的示例數據:

df <- data.frame("ID" = c(1,2,3,4))
df$`events.location.John.round.1` = 
list(list("A","B","C"),list("B","C","E"),list("A","C"),list("D","E","B"))
df$`events.location.John.round.2` = 
list(list("A","D","E"),NA,list("B","C"),list("B","E","C"))
df$`events.location.Mary.round.1` = list(NA,NA,list("B","C"),list("E","A"))
df$`events.location.Mary.round.2` = list(list("A","B","E"),NA,list("B","A"),list("D","E","C"))

LocationList <- c("A","B","C","D","E")
PersonList <- c("John", "Mary") 

我想遍歷位置和人員列表,以在數據框中生成新變量。 這是一些示例輸出:

df$`NumLocationsJohnRound1` = c(3,3,2,3)
df$`NumLocationsMaryRound1` = c(0,0,2,2)
df$`B.JohnRound1` = c(1,1,0,1)
df$`B.MaryRound1` = c(0,0,1,0)

用英語來說,第一個操作是“對於PersonList中的每個人,找到包含該人的姓名和其他文本的列名,然后返回該單元格列表的長度”

第二個操作是“對於PersonList中的每個人,找到包含該人姓名的列名,並為LocationList中的每個位置創建一個新的二進制字段,如果該列包含該位置, 則為 1。

基本上,我需要將所有新變量應用於匹配列,或者在單元格中的某個列表中搜索某個值。 這里的關鍵是一種靈活的方法,它可以遍歷列表,按名稱查找列並生成基於列表命名的新列。

我認為該解決方案取決於Regex/grep() ,但是我不知道如何將列表項插入到Regex字符串中(也許使用paste嗎?)。 select(contains())可能是步驟之一。

該解決方案可能purrr::map()dplyr::mutate()或涉及這些的自定義函數。 我想避免完全依賴於for循環。

我知道這是一個具有挑戰性的問題。 深入了解其中的任何內容(如何查找名稱中包含列表項的列,如何基於列表項創建具有名稱的新列,如何搜索列表列)將非常有幫助。

尚不完全清楚,但是基於“ Numlocations”輸出,可能會有所幫助

library(dplyr)
library(purrr)
nm1 <- sub("events", "Num", names(df)[-1])
df[nm1] <-  df[-1] %>% 
                  map(., ~lengths(.) *map_lgl(., ~ !all(is.na(.))))

對於第二部分,我們可以使用mtabulate獲得二進制輸出

library(qdapTools)
nm2 <-rep(paste0(names(df)[2:5], sub("events.location", "", names(df)[2:5])), each = 5) 
df[nm2] <- df[2:5] %>% 
                map(mtabulate) %>% 
                bind_cols

或者這可以在鏈中全部完成

nm3 <- sub("events.location", "", names(df)[2:5])
df[-1] %>%
  map_df(., ~lengths(.) *map_lgl(., ~ !all(is.na(.)))) %>% 
           rename_all(~nm1) %>%
           bind_cols(df, ., 
             df[-1] %>%
               map(., ~map(., ~factor(., levels = LETTERS[1:5]))) %>% 
               map(~as.data.frame.matrix(table(melt(.)[2:1]))) %>% 
               map2(., nm3, ~setNames(.x,  paste0(names(.x), .y))))

提供輸出

#ID events.location.John.round.1 events.location.John.round.2 events.location.Mary.round.1 events.location.Mary.round.2 Num.location.John.round.1
#1  1                      A, B, C                      A, D, E                           NA                      A, B, E                         3
#2  2                      B, C, E                           NA                           NA                           NA                         3
#3  3                         A, C                         B, C                         B, C                         B, A                         2
#4  4                      D, E, B                      B, E, C                         E, A                      D, E, C                         3
#  Num.location.John.round.2 Num.location.Mary.round.1 Num.location.Mary.round.2 A.John.round.1 B.John.round.1 C.John.round.1 D.John.round.1 E.John.round.1
#1                         3                         0                         3              1              1              1              0              0
#2                         0                         0                         0              0              1              1              0              1
#3                         2                         2                         2              1              0              1              0              0
#4                         3                         2                         3              0              1              0              1              1
#  A.John.round.2 B.John.round.2 C.John.round.2 D.John.round.2 E.John.round.2 A.Mary.round.1 B.Mary.round.1 C.Mary.round.1 D.Mary.round.1 E.Mary.round.1 A.Mary.round.2
#1              1              0              0              1              1              0              0              0              0              0              1
#2              0              0              0              0              0              0              0              0              0              0              0
#3              0              1              1              0              0              0              1              1              0              0              1
#4              0              1              1              0              1              1              0              0              0              1              0
#  B.Mary.round.2 C.Mary.round.2 D.Mary.round.2 E.Mary.round.2
#1              1              0              0              1
#2              0              0              0              0
#3              1              0              0              0
#4              0              1              1              1

使用dplyrpurrr解決方案

首先,使用mutate_at計算以“事件”開頭的所有列的列表長度。

library(dplyr)
library(purrr)

df2 <- df %>%
  mutate_at(vars(starts_with("events")), funs(`Len` = map(., ~length(.x[!is.na(.x)]))))

之后,設計一個函數來報告二進制結果。 將該函數應用於LocationList所有元素。 將結果存儲在loc_results

match_fun <- function(Location, df){
  df2 <- df %>%
    mutate_at(vars(starts_with("events")), 
              funs(!!Location := map_int(., ~as.integer(Location %in% unlist(.x))))) %>%
    select(ID, contains("_"))
  return(df2)
}

loc_results <- map(LocationList, match_fun, df = df)

最后,將loc_results所有數據幀合並為df3 ,然后將df2df3合並為df4 df4是最終輸出。

df3 <- reduce(loc_results, left_join, by = "ID")
df4 <- df2 %>% left_join(df3, by = "ID")

此解決方案考慮了命名約定。 下面是結果數據框。 如您所見,以_Len列顯示列表的長度,而以_A_B_C_D_E結尾的列顯示二進制結果。

df4

  ID events.location.John.round.1 events.location.John.round.2 events.location.Mary.round.1 events.location.Mary.round.2
1  1                      A, B, C                      A, D, E                           NA                      A, B, E
2  2                      B, C, E                           NA                           NA                           NA
3  3                         A, C                         B, C                         B, C                         B, A
4  4                      D, E, B                      B, E, C                         E, A                      D, E, C
  events.location.John.round.1_Len events.location.John.round.2_Len events.location.Mary.round.1_Len events.location.Mary.round.2_Len
1                                3                                3                                0                                3
2                                3                                0                                0                                0
3                                2                                2                                2                                2
4                                3                                3                                2                                3
  events.location.John.round.1_A events.location.John.round.2_A events.location.Mary.round.1_A events.location.Mary.round.2_A
1                              1                              1                              0                              1
2                              0                              0                              0                              0
3                              1                              0                              0                              1
4                              0                              0                              1                              0
  events.location.John.round.1_B events.location.John.round.2_B events.location.Mary.round.1_B events.location.Mary.round.2_B
1                              1                              0                              0                              1
2                              1                              0                              0                              0
3                              0                              1                              1                              1
4                              1                              1                              0                              0
  events.location.John.round.1_C events.location.John.round.2_C events.location.Mary.round.1_C events.location.Mary.round.2_C
1                              1                              0                              0                              0
2                              1                              0                              0                              0
3                              1                              1                              1                              0
4                              0                              1                              0                              1
  events.location.John.round.1_D events.location.John.round.2_D events.location.Mary.round.1_D events.location.Mary.round.2_D
1                              0                              1                              0                              0
2                              0                              0                              0                              0
3                              0                              0                              0                              0
4                              1                              0                              0                              1
  events.location.John.round.1_E events.location.John.round.2_E events.location.Mary.round.1_E events.location.Mary.round.2_E
1                              0                              1                              0                              1
2                              1                              0                              0                              0
3                              0                              0                              0                              0
4                              1                              1                              1                              1

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM