R分割具有NA的因子的数据帧

时间:2015-01-31 07:52:58

标签: r

我有从web导入的数据帧(df)。我对df的以下列(colname)感兴趣。 colname的元素被识别为"因素"。来自df的样本如下所示,其中还包括" NA" s:

colname
57 +0.10
55
NA
57,5 +2.00
56,5 +0.50
56,5
58

我想通过" +"分拆colname。并获得3个数字列,如下所示。 所需的输出是:

colname1 colname2 total
57.00    0.10     57.10
55.00    0.00     55.00
NA       NA       NA
57.50    2.00     59.50
56.50    0.50     57.00
56.50    0.00     56.50 
58.00    0.00     58.00

也是一个数据框,所有列都是数字。但是,我遇到了这个问题。无论我做什么,我都无法获得理想的结果。这些错误主要是由于" NA"和#34;因素"数据类型。我会很高兴得到任何帮助非常感谢。

3 个答案:

答案 0 :(得分:6)

我会使用sub将“,”替换为“。”。(read.table/read.csv也有dec选项。)使用cSplit中的splitstackshape ,将sep指定为,,将列拆分为两个。输出为data.table。使用rowSums创建“总计”列。如果要返回{{1对于所有NA的行,它是可能的(第二个解决方案中显示了一个选项)

NAs

或使用df$colname <- sub(',', '.', df$colname) library(splitstackshape) dt <- cSplit(df, 'colname', '+') dt[, Total:=rowSums(.SD,na.rm=TRUE)][] ,使用base R拆分列(“colname”)。输出将是“列表”。将“字符”转换为“数字”,填充strsplit以使所有列表元素和NAsrbind)的长度相同。按df2 <- do.call(...,)创建“总计”列,将两个列中rowSums的元素更改为NA

NAs

或者在这种情况下,也可以使用 lst <- lapply(strsplit(df$colname, '[+]'), as.numeric) df2 <- do.call(rbind.data.frame, lapply(lst, `length<-`, max(sapply(lst, length)))) names(df2) <- paste0('colname', 1:2) df2$Total <- (NA^!rowSums(!is.na(df2)))*rowSums(df2, na.rm=TRUE) df2 # colname1 colname2 Total #1 57.0 0.1 57.1 #2 55.0 NA 55.0 #3 NA NA NA #4 57.5 2.0 59.5 #5 56.5 0.5 57.0 #6 56.5 NA 56.5 #7 58.0 NA 58.0 ,这样可以避免将eval(parse(更改为0

的步骤
NA

更新

如果您需要将 df2$Total <- unname(sapply(df$colname, function(x) eval(parse(text=x)))) 替换为“colname2”中的NA

0

数据

df2$colname2[with(df2, is.na(colname2) & !is.na(colname1))] <- 0
 df2
 #  colname1 colname2 Total
 #1     57.0      0.1  57.1
 #2     55.0      0.0  55.0
 #3       NA       NA    NA
 #4     57.5      2.0  59.5
 #5     56.5      0.5  57.0
 #6     56.5      0.0  56.5
 #7     58.0      0.0  58.0

答案 1 :(得分:5)

这是另一个想法。您可以退后一步,并使用read.table()的许多参数。在这里我们可以使用sep = "+",因为该函数将剥离列之间的空格。

df <- read.table(text = x, col.names = c("V1", "V2"),
    colClasses = c(V1 = "numeric", V2 = "character"),
    dec = ",", skip = 1, fill = TRUE, sep = "+"
)

因此V2将成为删除了+个符号的字符列。因此,还有一些步骤可以使列成为数字并排列NA。为此,我们可以使用

within(df, {
    V2 <- replace(type.convert(V2), !nzchar(V2), 0)
    is.na(V2) <- is.na(V1)
    V3 <- V1 + V2
})
#     V1  V2   V3
# 1 57.0 0.1 57.1
# 2 55.0 0.0 55.0
# 3   NA  NA   NA
# 4 57.5 2.0 59.5
# 5 56.5 0.5 57.0
# 6 56.5 0.0 56.5
# 7 58.0 0.0 58.0

其中x

"colname\n57 +0.10\n55\nNA\n57,5 +2.00\n56,5 +0.50\n56,5\n58"

更新/改进:您也可以使用fread()和1.9.5中提供的新tstrsplit()功能执行此操作。这也允许您从文件中读取表而不先创建data.frame。

library(data.table)
fread(x, sep = "\n")[,
    tstrsplit(colname, "\\s?[+]", fill="0")][,
        lapply(.SD, function(x) type.convert(chartr(",", ".", x), as.is=TRUE))
    ][, V3 := rowSums(.SD)][]
#      V1  V2   V3
# 1: 57.0 0.1 57.1
# 2: 55.0 0.0 55.0
# 3:   NA 0.0   NA
# 4: 57.5 2.0 59.5
# 5: 56.5 0.5 57.0
# 6: 56.5 0.0 56.5
# 7: 58.0 0.0 58.0

答案 2 :(得分:4)

使用dplyrtidyr

library(tidyr)
library(dplyr)

df %>% 
  separate(colname, c("colname1", "colname2"), extra = "drop", convert = TRUE, '[+]') %>%
  mutate(colname1 = as.numeric(gsub(",", ".", colname1)),
         colname2 = ifelse(is.na(colname1), NA, ifelse(is.na(colname2), 0, colname2)), 
         total = colname1 + colname2)

你得到:

# colname1 colname2 total
#1     57.0      0.1  57.1
#2     55.0      0.0  55.0
#3       NA       NA    NA
#4     57.5      2.0  59.5
#5     56.5      0.5  57.0
#6     56.5      0.0  56.5
#7     58.0      0.0  58.0

NA不是colname2时(如您所需的输出中所示),colname1 NA中有0而不是{{1}}