[英]Create a new column in dplyr by appending values to a list from other columns?
我想通過附加到以其他列的值為條件的列表中來創建新列。 如果可能的話,我想在dplyr
這樣做。 樣本輸入和所需的輸出如下。
假設一個數據newdata
:
col1 col2 col3 col4
dog cat NA NA
NA cat foo bar
dog NA NA NA
NA cat NA NA
這是我想要的輸出,帶有新列newCol
:
col1 col2 col3 col4 newCol
dog cat NA NA (dog, cat)
NA cat foo bar (cat, foo, bar)
dog NA NA NA (dog)
NA cat NA bar (cat, bar)
我已經嘗試使用ifelse
內mutate
和case_when
內mutate
,但都不會允許拼接到列表中。 這是我對case_when
嘗試(失敗):
newdata = newdata %>% mutate(
newCol = case_when(
col1 == "dog" ~ c("dog"),
col2 == "cat" ~ c(newCol, "cat"),
col3 == "foo" ~ c(newCol, "foo"),
col4 == "bar" ~ c(newcol, "dog")
)
)
我嘗試了類似的方法,對每列使用ifelse
語句,但是也無法追加到列表中。
使用帶有collapse
參數的na.omit()
和paste()
解決方案:
apply(newdata, 1,
function(x) paste0("(", paste(na.omit(x), collapse = ", "), ")"))
[1] "(dog, cat)" "(cat, foo, bar)" "(dog)" "(cat)"
在最后的注釋中,我們顯示了此處使用的輸入數據。 就像在問題中一樣,只是我們在末尾添加了一行NA,以表明所有解決方案在這種情況下也適用。
我們同時顯示列表和字符列解決方案。 這個問題專門針對list,所以這是假定的期望輸出,但是如果打算將newCol
作為字符向量,那么我們也將其顯示出來。
使用基礎功能非常容易做到這一點,我們首先要說明。 但是,盡管它涉及更多的代碼,我們還是在tidyverse中重做了它。
1)base我們可以這樣使用apply
:
reduce <- function(x) unname(x[!is.na(x)])
DF$newCol <- apply(DF, 1, reduce)
給出以下內容,其中newCol
是其第一部分為c("dog", "cat")
等的列表。
col1 col2 col3 col4 newCol
1 dog cat <NA> <NA> dog, cat
2 <NA> cat foo bar cat, foo, bar
3 dog <NA> <NA> <NA> dog
4 <NA> cat <NA> <NA> cat
5 <NA> <NA> <NA> <NA>
最后一行代碼可能是:
DF$newCol <- lapply(split(DF, 1:nrow(DF)), reduce)
問題是連接到一個列表,所以我假設newCol
需要一個列表,但是如果需要一個字符串,則可以使用它作為reduce:
reduce_ch <- function(x) sprintf("(%s)", toString(x[!is.na(x)]))
apply(DF, 1, reduce_ch)
2)tidyverse或使用tpldyr / tidyr / tibble將其收集為長形,刪除NA,將其嵌套,將其排序回原始順序,然后將其與DF
綁定在一起。
library(dplyr)
library(tibble)
library(tidyr)
DF %>%
rownames_to_column %>%
gather(colName, Value, -rowname) %>%
na.omit %>%
select(-colName) %>%
nest(Value, .key = newCol) %>%
arrange(rowname) %>%
left_join(cbind(DF %>% rownames_to_column), .) %>%
select(-rowname)
給予:
col1 col2 col3 col4 newCol
1 dog cat <NA> <NA> dog, cat
2 <NA> cat foo bar cat, foo, bar
3 dog <NA> <NA> <NA> dog
4 <NA> cat <NA> <NA> cat
5 <NA> <NA> <NA> <NA> NULL
如果需要字符輸出,請改用以下命令:
DF %>%
rownames_to_column %>%
gather(colName, Value, -rowname) %>%
select(-colName) %>%
group_by(rowname) %>%
summarize(newCol = sprintf("(%s)", toString(na.omit(Value)))) %>%
ungroup %>%
{ cbind(DF, .) } %>%
select(-rowname)
給予:
col1 col2 col3 col4 newCol
1 dog cat <NA> <NA> (dog, cat)
2 <NA> cat foo bar (cat, foo, bar)
3 dog <NA> <NA> <NA> (dog)
4 <NA> cat <NA> <NA> (cat)
5 <NA> <NA> <NA> <NA> ()
輸入DF
重現形式:
Lines <- "col1 col2 col3 col4
dog cat NA NA
NA cat foo bar
dog NA NA NA
NA cat NA NA
NA NA NA NA"
DF <- read.table(text = Lines, header = TRUE, as.is = TRUE)
這看起來像是tidyr::unite
的用例。 最后,您仍然需要進行一些dplyr清理,但這現在應該可以進行。
library(tibble)
library(dplyr)
library(tidyr)
df <- tribble(~col1, ~col2, ~col3, ~col4,
"dog", "cat", NA, NA,
NA, "cat", "foo", "bar",
"dog", NA, NA, NA,
NA, "cat", NA, NA)
df %>%
unite(newCol, col1, col2, col3, col4,
remove = FALSE,
sep = ', ') %>%
# Replace NAs and "NA, "s with ''
mutate(newCol = gsub('NA[, ]*', '', newCol)) %>%
# Replace ', ' with '' if it is at the end of the line
mutate(newCol = gsub(', $', '', newCol)) %>%
# Add the parentheses on either side
mutate(newCol = paste0('(', newCol, ')'))
#> # A tibble: 4 x 5
#> newCol col1 col2 col3 col4
#> <chr> <chr> <chr> <chr> <chr>
#> 1 (dog, cat) dog cat <NA> <NA>
#> 2 (cat, foo, bar) <NA> cat foo bar
#> 3 (dog) dog <NA> <NA> <NA>
#> 4 (cat) <NA> cat <NA> <NA>
同樣出於價值,其他人也在討論這個問題 !
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.