我在R中有以下数据框,并尝试使用stringsplit函数来生成不同的数据框
DF
A B C
"1,2,3" "1,2"
"2" "1"
数据框的单元格用字符填充。空格是空白值。我创建了以下函数
sepfunc<-function(x){strsplit(as.character(x, split= ","))[[1]][1]}
当我在一个列上使用它时,该功能可以正常工作
sapply(DF$A, sepfunc)
[1] "1" "2"
但是,以下命令仅产生一行
sapply(DF, sepfunc)
A B C
"1" NA "1"
不显示第二行。我知道我必须遗漏一些简陋的东西。我请求别人帮忙。
预期输出
A B C
"1" NA "1"
"2" "1" "NA"
答案 0 :(得分:3)
当我们执行strsplit
时,输出为list
个vector
。如果我们只使用list
对第一个[[1]]
元素进行子集化,则会跳过其余元素。这里第一个元素对应第一行。但是,当我们在一个列上执行相同操作时,它会循环遍历每个元素,然后执行strsplit。取第一个元素[[1]]
不会有害,因为list
长度为1.这里的情况不同。 list
元素的数量与每列的行数相同。所以,我们需要循环遍历list
(使用sapply/lapply
- 前者给出一个向量取决于大小写,而后者总是返回list
)
sapply(DF, function(x) sapply(strsplit(as.character(x), ","), `[`, 1))
# A B C
#[1,] "1" NA "1"
#[2,] "2" "1" NA
让我们通过将代码分成块来更仔细地看待它。在每列上,我们可以找到分割list
s
vector
lapply(DF, function(x) strsplit(as.character(x), ","))
#$A
#$A[[1]]
#[1] "1" "2" "3"
#$A[[2]]
#[1] "2"
#$B
#$B[[1]]
#[1] NA
#$B[[2]]
#[1] "1"
#$C
#$C[[1]]
#[1] "1" "2"
#$C[[2]]
#character(0)
当我们[[1]]
时,第一个元素被提取,即第一行'A','B','C'
lapply(DF, function(x) strsplit(as.character(x), ",")[[1]])
#$A
#[1] "1" "2" "3"
#$B
#[1] NA
#$C
#[1] "1" "2"
如果我们再次对上面的元素(即第一个元素)进行子集化,则输出将为1 NA 1
。
相反,我们希望遍历list
并获取每个list
的第一个元素
答案 1 :(得分:2)
由于您只想在,
之前提取第一部分,您也可以
sapply(DF, function(x) gsub("^([^,]*),.*$", "\\1", x))
# A B C
# [1,] "1" NA "1"
# [2,] "2" NA "1"
这将提取第一组(\\1
),此处标有括号。 ([^,]*)
或stringr
:
library(stringr)
sapply(DF, function(x) str_extract(x, "^([^,]*)"))
答案 2 :(得分:1)
这是
的另一个版本lapply(X = df, FUN = function(x) sapply(strsplit(x = as.character(x), split = ","), FUN = head, n=1))
答案 3 :(得分:1)
首先,请注意您的sepfun
应始终出错:
sepfunc<-function(x){strsplit(as.character(x, split= ","))[[1]][1]}
split
应该与strsplit
一起使用,而不是as.character
,所以你的意思可能是:
sepfunc<-function(x){strsplit(as.character(x), split= ",")[[1]][1]}
第二,数据健全性问题。您将字符变量存储为因子,并将缺少的数据存储为空字符串。在尝试做任何其他事情之前,我建议处理这些问题。 (为什么我说NA
在这里比空字符串更明智?因为你告诉我了。你想在输出中NA
,所以我想这意味着如果有的话字符串中没有数字,这意味着缺少某些东西。缺少= NA
。还有一个技术原因需要更长的时间才能解释。)
所以在下文中,我只使用了DF
的更改版本:
DF <- data.frame(A=c("1,2,3", "2"), B=c(NA, "1"), C=c("1,2", NA), stringsAsFactors=FALSE)
(如果DF来自文件,那么您可以使用read.csv("file", as.is=TRUE)
。然后使用DF[DF==""] <- NA
。)
strsplit
的输出为list
,因此您需要sapply
才能从中获取有用的内容。另一个sapply
将其应用于数据框中的所有列。
sapply(DF, function(x) sapply(strsplit(x, ","), head, 1))
# A B C
# [1,] "1" NA "1"
# [2,] "2" "1" NA
或一步一步。在sapply
对数据框的所有列进行函数之前,需要它为所有列提供有意义的结果。试试吧:
sf <- function(x) sapply(strsplit(x, ","), head, 1)
# and sepfunc as defined above:
sepfunc<-function(x){strsplit(as.character(x), split= ",")[[1]][1]}
sf(DF$A)
# [1] "1" "2"
# as expected
sepfunc(DF$A)
# [1] "1"
请注意,sepfunc
仅使用每列的第一个元素(如您所说!),其余元素将被丢弃。您需要sapply
或类似的东西才能使用所有元素。因此,你得到了这个:
sapply(DF, sepfunc)
# A B C
# "1" NA "1"
(它有效,因为我们已经将空字符串重新定义为NA。但是只能获得每个变量的第一行的结果。)
sapply(DF, sf)
# A B C
# [1,] "1" NA "1"
# [2,] "2" "1" NA