【问题标题】:R: Replacing a factor with an integer value in numerous cells across numerous columnsR:在许多列的许多单元格中用整数值替换一个因子
【发布时间】:2016-05-25 08:39:04
【问题描述】:

因此,我的挑战是将原始比例 csv 转换为评分 csv。在众多列中,该文件的单元格中填充了“非常同意”到“非常不同意”,共 6 个级别。这些因子需要分别转换成整数5到0。

我尝试使用 sapply 并将表格转换为字符串,但没有成功。 Sapply 对向量起作用,但它破坏了表结构。

方法一:

dat$Col<-sapply(dat$Col,switch,'Strongly Disagree'=0,'Disagree'=1,'Slightly Disagree'=2,'Slightly Agree'=3,'Agree'=4, 'Strongly Agree'=5)

我的第二种方法是将 csv 转换为字符串。当我检查 dput 输出时,我看到我想要定位的区域以 .Label="","Strongly Agree" 开头... 错误。我的更改没有产生有用的结果。

我的第三种方法来自互联网破坏之神,他们似乎表示 gsub() 也可以处理字符串方法。不,基础表结构又被破坏了。

方法#3:转换成字符串和模式匹配

dat <- textConnection("control/Surveys/StudyDat_1.csv")
#Score Scales
##"Strongly Agree"= 5
##"Agree"= 4
##"Strongly Disagree" = 0
#levels(dat$Col) <- gsub("Strongly Agree", "5", levels(dat$Col))
    df<- gsub("Strongly Agree", "5",dat)
    dat<-read.csv(textConnection(df),header=TRUE)

最后,我想在众多列中将所有“强烈同意”替换为 5,而不会破坏数据的可检索性。

也许我使用了错误的搜索字符串,而您知道解决此问题所需的资源。我宁愿避免使用所有字符向量方法,因为如果您提供代码响应,这将需要标记每一列。它需要遍历所有列。

谢谢

数据样本问题

    structure(list(last_updated = structure(c(3L, 1L, 7L, 2L, 10L, 6L, 8L, 9L, 7L, 5L, 4L), .Label = c("2016-05-13T12:53:56.704184Z", 
"2016-05-13T12:54:09.273359Z", "2016-05-13T12:54:22.757251Z", 
"2016-05-14T12:44:13.474992Z", "2016-05-14T12:44:31.736469Z", 
"2016-05-16T16:45:10.623410Z", "2016-05-16T16:46:17.881402Z", 
"2016-05-16T16:46:55.122257Z", "2016-05-16T16:47:14.160793Z", 
"2016-05-24T02:26:04.770799Z"), class = "factor"), feedback = c(NA, 
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), A = structure(c(NA, 
NA, 2L, NA, 1L, NA, NA, NA, 2L, NA, NA), .Label = c("", "Slightly Disagree"
), class = "factor"), B = structure(c(NA, NA, 2L, NA, 1L, NA, 
NA, NA, 3L, NA, NA), .Label = c("", "Disagree", "Strongly Agree"
), class = "factor"), C = structure(c(NA, NA, 2L, NA, 1L, NA, 
NA, NA, 3L, NA, NA), .Label = c("", "Agree", "Disagree"), class = "factor"), 
    D = structure(c(NA, NA, 2L, NA, 1L, NA, NA, NA, 2L, NA, NA
    ), .Label = c("", "Agree"), class = "factor"), E = structure(c(NA, 
    NA, 2L, NA, 1L, NA, NA, NA, 3L, NA, NA), .Label = c("", "Agree", 
    "Strongly Disagree"), class = "factor")), .Names = c("last_updated", 
"feedback", "A", "B", "C", "D", "E"), class = "data.frame", row.names = c(NA, 
-11L))

数据样本解决方案

df<-dget(structure(list(last_updated = structure(c(3L, 1L, 7L, 2L, 10L,   6L,8L, 9L, 7L, 5L, 4L), .Label = c("2016-05-13T12:53:56.704184Z", 
"2016-05-13T12:54:09.273359Z", "2016-05-13T12:54:22.757251Z", 
"2016-05-14T12:44:13.474992Z", "2016-05-14T12:44:31.736469Z", 
"2016-05-16T16:45:10.623410Z", "2016-05-16T16:46:17.881402Z", 
"2016-05-16T16:46:55.122257Z", "2016-05-16T16:47:14.160793Z", 
"2016-05-24T02:26:04.770799Z"), class = "factor"), feedback = c(NA, 
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), A = c(NA, NA, 2L, NA, 
NA, NA, NA, NA, 2L, NA, NA), B = c(NA, NA, 1L, NA, NA, NA, NA, 
NA, 5L, NA, NA), C = c(NA, NA, 4L, NA, NA, NA, NA, NA, 1L, NA, 
NA), D = c(NA, NA, 4L, NA, NA, NA, NA, NA, 4L, NA, NA), E = c(NA, 
NA, 4L, NA, NA, NA, NA, NA, 0L, NA, NA)), .Names = c("last_updated", 
"feedback", "A", "B", "C", "D", "E"), class = "data.frame", row.names =    c(NA,-11L)))

【问题讨论】:

  • 您的“数据样本解决方案”有误;第 9 行 A 列应该是 2,而不是 4。

标签: r


【解决方案1】:

我们可以使用factor 指定levels

 nm1 <- c('Strongly Disagree', 'Disagree',
     'Slightly Disagree','Slightly Agree','Agree', 'Strongly Agree')

 factor(dat$col, levels = nm1,
         labels = 0:5))

如果有多个具有相同级别的factor 列,则标识factor 列('i1'),使用lapply 循环并指定levelslabels

i1 <- sapply(dat, is.factor)
dat[i1] <- lapply(dat[i1], factor, levels = nm1, labels= 0:5)

更新

使用 OP 的 dput 输出

dat[-(1:2)] <- lapply(dat[-(1:2)], factor, levels = nm1, labels = 0:5)
dat
#                last_updated feedback    A    B    C    D    E
#1  2016-05-13T12:54:22.757251Z       NA <NA> <NA> <NA> <NA> <NA>
#2  2016-05-13T12:53:56.704184Z       NA <NA> <NA> <NA> <NA> <NA>
#3  2016-05-16T16:46:17.881402Z       NA    2    1    4    4    4
#4  2016-05-13T12:54:09.273359Z       NA <NA> <NA> <NA> <NA> <NA>
#5  2016-05-24T02:26:04.770799Z       NA <NA> <NA> <NA> <NA> <NA>
#6  2016-05-16T16:45:10.623410Z       NA <NA> <NA> <NA> <NA> <NA>
#7  2016-05-16T16:46:55.122257Z       NA <NA> <NA> <NA> <NA> <NA>
#8  2016-05-16T16:47:14.160793Z       NA <NA> <NA> <NA> <NA> <NA>
#9  2016-05-16T16:46:17.881402Z       NA    2    5    1    4    0
#10 2016-05-14T12:44:31.736469Z       NA <NA> <NA> <NA> <NA> <NA>
#11 2016-05-14T12:44:13.474992Z       NA <NA> <NA> <NA> <NA> <NA>

另一个选项是set 来自data.table

library(data.table)
for(j in names(dat)[-(1:2)]){
  set(dat, i = NULL, j= j, value = factor(dat[[j]], levels = nm1, labels = 0:5))
 }

【讨论】:

  • 我们也可以用ordered代替factor来表示序数数据
【解决方案2】:

我只需将每个目标列向量匹配到预先计算的字符向量中即可获得整数索引。您可以在之后减去 1 以将范围从 1:6 更改为 0:5。

## define desired value order, ascending
o <- c(
    'Strongly Disagree',
    'Disagree',
    'Slightly Disagree',
    'Slightly Agree',
    'Agree',
    'Strongly Agree'
);

## convert target columns
for (cn in names(df)[-(1:2)]) df[[cn]] <- match(as.character(df[[cn]]),o)-1L;
df;
##                   last_updated feedback  A  B  C  D  E
## 1  2016-05-13T12:54:22.757251Z       NA NA NA NA NA NA
## 2  2016-05-13T12:53:56.704184Z       NA NA NA NA NA NA
## 3  2016-05-16T16:46:17.881402Z       NA  2  1  4  4  4
## 4  2016-05-13T12:54:09.273359Z       NA NA NA NA NA NA
## 5  2016-05-24T02:26:04.770799Z       NA NA NA NA NA NA
## 6  2016-05-16T16:45:10.623410Z       NA NA NA NA NA NA
## 7  2016-05-16T16:46:55.122257Z       NA NA NA NA NA NA
## 8  2016-05-16T16:47:14.160793Z       NA NA NA NA NA NA
## 9  2016-05-16T16:46:17.881402Z       NA  2  5  1  4  0
## 10 2016-05-14T12:44:31.736469Z       NA NA NA NA NA NA
## 11 2016-05-14T12:44:13.474992Z       NA NA NA NA NA NA

【讨论】:

    【解决方案3】:

    以前的答案可能满足您的需求,但请注意,更改因子的 标签 与将因子更改为整数变量不同。一种可能性是使用ifelse(我创建了一个新数据框,因为您发布的数据框实际上并没有包含这些级别的变量):

    lev <- c('Strongly disagree', 'Disagree', 'Slightly disagree', 'Slightly agree', 'Agree', 'Strongly agree')
    
    dta <- sample(lev, 55, replace = TRUE)
    dta <- data.frame(matrix(dta, nrow = 11))
    names(dta) <- LETTERS[1:5]
    
    f_to_int <- function(f) {
      if (is.factor(f)){
       ifelse(f == 'Strongly disagree', 0, 
         ifelse(f == 'Disagree', 1, 
           ifelse(f == 'Slightly disagree', 2,`` 
             ifelse(f == 'Slightly agree', 3,
               ifelse(f == 'Agree', 4,
                 ifelse(f == 'Strongly agree', 5, f))))))
      } else f
    }
    
    dta2 <- sapply(dta, f_to_int)
    

    请注意,这会返回一个矩阵,但如果需要,它很容易转换为数据框。

    【讨论】:

    • 运行as.integer(as.character(fac)) 将因子转换为整数更容易(如果标签是字符串中的整数)。否则,如果标签已经正确排序,您可以直接使用as.integer(fac)(并且可能使用-1进行调整为什么要使用嵌套ifelse?您的代码只是一种?switch。OP的原始解决方案是更好!
    • OP 说他的解决方案不起作用。我同意,您提出的解决方案更容易,但它只在某些情况下有效。如果数据类似于我生成的数据框,则使用 as.integer(as.character(fac)) 会产生 NA。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-11
    • 2016-06-05
    • 2021-11-24
    • 1970-01-01
    • 2018-11-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多