【问题标题】:R subset exclusion based on string creates extra column基于字符串的 R 子集排除创建额外的列
【发布时间】:2018-12-28 12:02:40
【问题描述】:

我有一个如下的数据集

salaries <- read.csv('salaries.csv', header=TRUE)
print(salaries)

Name    Job         Salary  CompanyExperience   IndustryExperience
John    Engineer    50000       3               12
Adam    Manager     55000       6               7
Alice   Manager     #N/A        6               6
Bob     Engineer    65000       5               #N/A
Carl    Engineer    70000       #N/A            10

我想绘制其中的一些信息,但是我需要通过删除任何包含“#N/A”文本字符串的行(由 MS Excel 生成)来排除任何带有“#N/A”的数据点导出到 CSV 的电子表格)以绘制 Salary ~ CompanyExperience。 我的子集代码如下:

salaries <-salaries[salaries$CompanyExperience!="#N/A" & 
salaries$Salary!="#N/A",]
#write.csv(salaries, "salaries2.csv")
#salaries <- read.csv('salaries2.csv', header=TRUE)
print(salaries)

现在这似乎没有任何问题,产生:

  Name      Job Salary     CompanyExperience     IndustryExperience
1 John Engineer  50000                 3                 12
2 Adam  Manager  55000                 6                  7
4  Bob Engineer  65000                 5               #N/A

这看起来不错,但是一旦我尝试将此数据子集放入线性回归中,就会出现错误:

> salarylinear <- lm(salaries$CompanyExperience ~ salaries$Salary)
Warning messages:
1: In model.response(mf, "numeric") :
  using type = "numeric" with a factor response will be ignored
2: In Ops.factor(y, z$residuals) : ‘-’ not meaningful for factors

现在,如果我做了一些实验并发现如果我使用“!= 10000”或“

  X Name      Job     Salary     CompanyExperience     IndustryExperience
1 1 John     Engineer  50000                 3                 12
2 2 Adam     Manager   55000                 6                  7
3 4 Bob      Engineer  65000                 5               #N/A

我已经在网上搜索过,但找不到发生这种情况的任何原因。有没有一种方法可以通过排除“#N/A”字符串来生成可用的子集,而不必求助于将数据写入磁盘并再次读入内存?

【问题讨论】:

    标签: r string subset rows


    【解决方案1】:

    跟进我们在 cmets 中关于使用矩阵对 data.frame 进行子集化时会发生什么的讨论:

    首先,我们创建一个 3x2 数据框来使用:

    df <- data.frame(x=1:3, y=4:6)
    

    然后,让我们创建一个TRUE/FALSE 向量,用于在对数据框进行子集化时要保留的行。

    v <- c(T,T,F)
    

    这里,v 有 2 个 TRUEs 后跟 1 个 FALSE,所以如果我们用 v 子集我们的 3 行数据帧,我们将选择前 2 行并省略第 3 行:

    df[v,]
      x y
    1 1 4
    2 2 5
    

    太好了,按预期工作。但是如果我们用一个矩阵子集呢?我们创建矩阵m,它与我们的数据框具有相同的 3x2 维度。 m 充满了 TRUEs,除了单元格 (1,1) 和 (3,2) 中的 2 个 FALSEs。

    m <- matrix(c(F,T,T,T,T,F), ncol=2)
    m
          [,1]  [,2]
    [1,] FALSE  TRUE
    [2,]  TRUE  TRUE
    [3,]  TRUE FALSE
    

    现在,如果我们尝试使用 m 对我们的数据框进行子集化,我们一开始可能会认为我们只会返回第 2 行,因为 m 在其第一行和第三行中有一个 FALSE。当然,事实并非如此。

    df[m,]
          x  y
    2     2  5
    3     3  6
    NA   NA NA
    NA.1 NA NA
    

    理解这一点的诀窍是要知道 R 中的矩阵只是一个具有维度属性的向量。维度符合预期,因为我们创建了m

    dim(m)
    [1] 3 2
    

    但作为向量,m 长什么样子:

    as.vector(m)
    [1] FALSE  TRUE  TRUE  TRUE  TRUE FALSE
    

    我们看到m-as-a-vector 只是m 的列,一个接一个地重复(因为R“填充”矩阵列)。让我用识别的原始单元格重写m,以防我的描述不清楚:

    [1] FALSE   TRUE   TRUE   TRUE   TRUE   FALSE
        (1,1)   (2,1)  (3,1)  (1,2)  (2,2)  (3,2)
    

    因此,当我们尝试使用 m 对数据帧进行子集化时,就像使用这个长度为 6 的向量,而这个长度为 6 的向量表示选择行 2:5。所以当我们写df[m, ]时,R忠实地选择了第2行和第3行,然后当它尝试选择第4行和第5行时,它们并不“存在”,所以R用NAs填充它们。这就是为什么我们在子集中得到更多行而不是在原始数据框中。

    最后,我们看到df[m, ] 有一些有趣的行名,例如NA.1。行名必须是唯一的,因此 R 将“子集”的第 4 行称为“NA”,并调用“NA.1”子集的第 5 行。

    我希望这可以为您解决问题。编码愉快!

    【讨论】:

      【解决方案2】:

      最有可能发生的情况是,您认为是数字的数据列实际上不是数字的。有两件事导致了这一点:

      1. read.csv() 不知道“#N/A”的意思是“缺失”,因此,它将“#N/A”作为字符串(不是数字)读取,导致它认为整个列of Salary、CompanyExperience 和 IndustryExperience 是字符串变量。
      2. read.csv() 有一个臭名昭著的默认读取字符串作为因子。如果您对因子不熟悉,this 是一种很好的资源。

      这种事件组合是 lm() 认为您的因变量是一个因素并引发错误的原因。

      解决方案是将na.strings = "#N/A" 作为参数添加到read.csv()。然后您的数据将作为数字读入。您可以直接运行回归,因为lm() 会自动删除带有 NA 的行。

      但是,为了更明确一点,您可能还想将 stringsAsFactors = FALSE 作为参数添加到 read.csv(),以防万一您有任何其他表示“丢失”但被编码为空白的东西.而且,如果您想在运行回归之前手动处理 NA,您可以使用 complete.cases() 或类似 salaries[!is.na(Salary),] 的方式删除带有 NA 的行

      【讨论】:

      • 我尝试了代码“Salaries
      • 您要做的是选择行的子集。执行此操作的最简单表达式类似于mydf[myvec, ],其中myvec 包含应保留在子集中的行的TRUE 和应删除的行的FALSE。请注意您在子集上的两次尝试之间的区别:complete.cases() 返回一个 vector 并且该向量的长度与 data.frame 中的行数相同;这就是你想要的。 !(is.na()) 返回一个与您的 data.frame 具有相同维度的 matrix不是你想要的。
      • 但是 !is.na() 返回的矩阵与我的 data.frame 不同(更大)维度,这让我感到困惑。这就是我的意思imgur.com/a/X6cDxhA 这里。
      • 我将发布一个新的“答案”,并附上一个示例,向您展示发生了什么...
      猜你喜欢
      • 1970-01-01
      • 2022-06-17
      • 2019-06-05
      • 2017-01-21
      • 2021-04-28
      • 2019-07-16
      • 1970-01-01
      • 1970-01-01
      • 2018-06-10
      相关资源
      最近更新 更多