Ben Bolker のpaste2
- solutionは、貼り付けられた文字列に同じ位置にNA
が含まれている場合に""
を生成します。このような、
> paste2(c("a","b", "c", NA), c("A","B", NA, NA))
[1] "a, A" "b, B" "c" ""
4番目の要素はNA
ではなく""
ですこのように、
[1] "a, A" "b, B" "c" NA
これを修正できる人にこの小さな賞金を提供しています。
ヘルプページ?paste
を読みましたが、RにNA
sを無視させる方法がわかりません。私は次のことを行います
foo <- LETTERS[1:4]
foo[4] <- NA
foo
[1] "A" "B" "C" NA
paste(1:4, foo, sep = ", ")
そして得る
[1] "1, A" "2, B" "3, C" "4, NA"
欲しいもの、
[1] "1, A" "2, B" "3, C" "4"
こんなことができた
sub(', NA$', '', paste(1:4, foo, sep = ", "))
[1] "1, A" "2, B" "3, C" "4"
しかし、それは回り道のようです。
「true-NA」の目的:最も直接的なルートは、値がpaste2
のときに""
によって返される値をNA
に変更することです
paste3 <- function(...,sep=", ") {
L <- list(...)
L <- lapply(L,function(x) {x[is.na(x)] <- ""; x})
ret <-gsub(paste0("(^",sep,"|",sep,"$)"),"",
gsub(paste0(sep,sep),sep,
do.call(paste,c(L,list(sep=sep)))))
is.na(ret) <- ret==""
ret
}
val<- paste3(c("a","b", "c", NA), c("A","B", NA, NA))
val
#[1] "a, A" "b, B" "c" NA
私はこの質問が何年も前のものであることを知っていますが、r paste na
。私は、単純な問題だと思っていたものの簡単な解決策を探していましたが、答えの複雑さに多少驚いていました。私は別のソリューションを選択し、他の誰かが興味を持っている場合に備えてここに投稿しています。
bar <- apply(cbind(1:4, foo), 1, function(x) paste(x[!is.na(x)], collapse = ", "))
bar
[1] "1, A" "2, B" "3, C" "4"
明らかでない場合、これは、任意の位置にNAを持つ任意の数のvecotrで機能します。
私見、既存の答えに対するこれの利点は読みやすさです。これはワンライナーで、常にニースであり、同僚や将来の自分をつまずかせる可能性のある一連の正規表現やif/elseステートメントに依存していません。 Erik Shittsの答え はほとんどこれらの利点を共有していますが、2つのベクトルのみがあり、最後のベクトルのみがNAを含むと想定しています。
私のプロジェクトは反対の要件を持っているため、私のソリューションは編集の要件を満たしていません。ただし、 42-'s answer から借用した2行目を追加することで、これを簡単に解決できます。
is.na(bar) <- bar == ""
@ErikShiltの回答と@agstudyのコメントをフォローする関数。 sep
の指定を許可し、any要素(最初、最後、または中間)がNA
であるケースを処理することにより、状況を少し一般化します。 (行に複数のNA
値がある場合、または他のトリッキーな場合に破損する可能性があります...)ところで、この状況は?paste
のDetails
セクションの2番目の段落で正確に説明されていることに注意してくださいは、少なくともRの作成者が状況を認識していることを示します(ただし、ソリューションは提供されません)。
paste2 <- function(...,sep=", ") {
L <- list(...)
L <- lapply(L,function(x) {x[is.na(x)] <- ""; x})
gsub(paste0("(^",sep,"|",sep,"$)"),"",
gsub(paste0(sep,sep),sep,
do.call(paste,c(L,list(sep=sep)))))
}
foo <- c(LETTERS[1:3],NA)
bar <- c(NA,2:4)
baz <- c("a",NA,"c","d")
paste2(foo,bar,baz)
# [1] "A, a" "B, 2" "C, 3, c" "4, d"
これは、@ agstudyの(1)オプションのcollapse
引数を組み込むという提案を処理しません。 (2)na.rm
引数を追加して、NA
- removalをオプションにします(デフォルトをFALSE
に設定して、paste2
とpaste
との後方互換性を確保します)。これをもっと洗練したい(つまり、複数の連続したNA
sを削除したい)場合は、Rcppを使用してC++で記述するのが理にかなっています(C++の文字列処理についてはあまり知りませんが、それほど難しくないかもしれません- Rcpp :: CharacterVectorをstd :: stringに変換 および 文字列の連結が期待どおりに機能しない を参照してください...)
Ben Bolker で述べたように、複数のNAが連続している場合、上記のアプローチは失敗するかもしれません。これを克服するように見える別のアプローチを試しました。
_paste4 <- function(x, sep = ", ") {
x <- gsub("^\\s+|\\s+$", "", x)
ret <- paste(x[!is.na(x) & !(x %in% "")], collapse = sep)
is.na(ret) <- ret == ""
return(ret)
}
_
2行目は、テキストと数字を連結するときに導入される余分な空白を取り除きます。上記のコードは、apply
コマンドを使用してデータフレームの複数の列(または行)を連結するために使用するか、必要に応じて最初にデータをデータフレームに強制するために再パッケージ化できます。
_EDIT
_
さらに数時間後、次のコードには上記の提案が組み込まれ、collapseオプションとna.rmオプションを指定できるようになったと思います。
_paste5 <- function(..., sep = " ", collapse = NULL, na.rm = F) {
if (na.rm == F)
paste(..., sep = sep, collapse = collapse)
else
if (na.rm == T) {
paste.na <- function(x, sep) {
x <- gsub("^\\s+|\\s+$", "", x)
ret <- paste(na.omit(x), collapse = sep)
is.na(ret) <- ret == ""
return(ret)
}
df <- data.frame(..., stringsAsFactors = F)
ret <- apply(df, 1, FUN = function(x) paste.na(x, sep))
if (is.null(collapse))
ret
else {
paste.na(ret, sep = collapse)
}
}
}
_
上記のように、na.omit(x)
を_(x[!is.na(x) & !(x %in% "")
_に置き換えて、必要に応じて空の文字列も削除できます。 na.rm = Tでcollapseを使用すると、「NA」のない文字列が返されますが、これはコードの最後の行をpaste(ret, collapse = collapse)
に置き換えることで変更できます。
_nth <- paste0(1:12, c("st", "nd", "rd", rep("th", 9)))
mnth <- month.abb
nth[4:5] <- NA
mnth[5:6] <- NA
paste5(mnth, nth)
[1] "Jan 1st" "Feb 2nd" "Mar 3rd" "Apr NA" "NA NA" "NA 6th" "Jul 7th" "Aug 8th" "Sep 9th" "Oct 10th" "Nov 11th" "Dec 12th"
paste5(mnth, nth, sep = ": ", collapse = "; ", na.rm = T)
[1] "Jan: 1st; Feb: 2nd; Mar: 3rd; Apr; 6th; Jul: 7th; Aug: 8th; Sep: 9th; Oct: 10th; Nov: 11th; Dec: 12th"
paste3(c("a","b", "c", NA), c("A","B", NA, NA), c(1,2,NA,4), c(5,6,7,8))
[1] "a, A, 1, 5" "b, B, 2, 6" "c, , 7" "4, 8"
paste5(c("a","b", "c", NA), c("A","B", NA, NA), c(1,2,NA,4), c(5,6,7,8), sep = ", ", na.rm = T)
[1] "a, A, 1, 5" "b, B, 2, 6" "c, 7" "4, 8"
_
ベクトル化されたif-elseコンストラクトであるifelse
を使用して、値がNAであるかどうかを判断し、空白を置き換えることができます。次に、他の文字列が後に続かない場合、gsubを使用して末尾の「、」を取り除きます。
gsub(", $", "", paste(1:4, ifelse(is.na(foo), "", foo), sep = ", "))
あなたの答えは正しいです。それを行うより良い方法はありません。この問題は、詳細セクションの ドキュメントの貼り付け で明示的に言及されています。
または、paste()の後にmutateを実行し、NAを削除します。
data <- data.frame(col1= c(rep(NA, 5)), col2 = c(2:6)) %>%
mutate(col3 = paste(col1, col2)) %>%
mutate(col3 = gsub('NA', '', col3))
または、str_replace_allを使用して貼り付けた後、NAを削除します
data$1 <- str_replace_all(data$1, "NA", "")