![](/img/trans.png)
[英]How to loop through the columns in an R data frame and create a new data frame using the column name in each iteration?
[英]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
使用dplyr
和purrr
解決方案
首先,使用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
,然后將df2
和df3
合並為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.