这是我的数据框:
x1 <- c("a", "c", "f", "j")
x2 <- c("b", "c", "g", "k")
x3 <- c("b", "d", "h", NA)
x4 <- c("a", "e", "i", NA)
df <- data.frame(x1, x2, x3, x4, stringsAsFactors=F)
df
x1 x2 x3 x4
1 a b b a
2 c c d e
3 f g h i
4 j k <NA> <NA>
使用
apply(df, 1, paste, collapse = "_")
给了我
[1] "a_b_b_a" "c_c_d_e" "f_g_h_i" "j_k_NA_NA"
我想忽略这些NA,所以最后得到的元素应该是&#34; j_k&#34;而不是&#34; j_k_NA_NA&#34;。
非常感谢您的支持。
拉米
答案 0 :(得分:3)
使用您的代码,
apply(df, 1, function(x) paste(na.omit(x), collapse="_") )
#[1] "a_b_b_a" "c_c_d_e" "f_g_h_i" "j_k"
另一种选择是
df[is.na(df)] <-''
gsub("^_+|_+$", "", do.call(paste,c(df, sep="_")))
#[1] "a_b_b_a" "c_c_d_e" "f_g_h_i" "j_k"
如果有内部NAs,也许这有效
gsub("^_+|_+$|_+(?=_)", "", do.call(paste,c(df, sep="_")), perl=TRUE)
或基于@David Arenburg的评论
gsub("NA_|_NA", "", apply(df, 1, paste, collapse = "_"))
例如
v1 <- c(NA,'a', 'b', NA, NA, NA, 'c',NA, 'd', NA)
v1[is.na(v1)] <-''
gsub("^_+|_+$|_+(?=_)", "", paste(v1, collapse="_"), perl=TRUE)
#[1] "a_b_c_d"
答案 1 :(得分:2)
以下是使用zoo
包
library(zoo)
gsub("NA_|_NA", "", rollapply(t(df), width = 4, FUN = paste, collapse = "_"))
## [,1] [,2] [,3] [,4]
## [1,] "a_b_b_a" "c_c_d_e" "f_g_h_i" "j_k"
答案 2 :(得分:1)
@ akrun的第二个选项很可能是最快的,但你也可以考虑这样的事情:
library(data.table)
na.omit(data.table(
rn = rep(1:nrow(df), ncol(df)),
val = unlist(df, use.names = FALSE)))[, paste(val, collapse = "_"), by = rn]
# rn value
# 1: 1 a_b_b_a
# 2: 2 c_c_d_e
# 3: 3 f_g_h_i
# 4: 4 j_k
基本想法是从“长”data.table
开始,删除NA
值,然后将剩余值粘贴在一起。
对于此特定示例,在速度方面使用na.omit
会产生大差异。
以下是一些使用相同样本数据(100K行)I shared at a related question的基准测试。
这些是我测试的功能:
AM <- function() {
na.omit(data.table(
rn = rep(1:nrow(df), ncol(df)),
val = unlist(df, use.names = FALSE)))[, paste(val, collapse = "_"), by = rn]
}
AK <- function() {
df[is.na(df)] <-''
gsub("^_+|_+$|_+(?=_)", "", do.call(paste,c(df, sep="_")), perl=TRUE)
}
RS <- function() {
s <- split(df[!is.na(df)], row(df)[!is.na(df)])
vapply(s, paste, character(1L), collapse = "_", USE.NAMES=FALSE)
}
结果:
microbenchmark(AM(), AK(), RS(), times = 50)
# Unit: milliseconds
# expr min lq mean median uq max neval
# AM() 819.4639 925.1636 1020.5084 979.6239 1118.8065 1384.873 50
# AK() 490.6802 495.5576 559.4551 508.0861 602.8413 1192.798 50
# RS() 1419.8630 1540.5424 1680.6115 1622.7701 1786.9931 2424.541 50
答案 3 :(得分:1)
您可以在删除了NA值的列表中使用vapply
。这似乎是安全的。
> s <- split(df[!is.na(df)], row(df)[!is.na(df)])
> vapply(s, paste, character(1L), collapse = "_", USE.NAMES=FALSE)
[1] "a_b_b_a" "c_c_d_e" "f_g_h_i" "j_k"