【问题标题】:In R, how do I classify each row of a data frame based on the bin its values fall into?在 R 中,如何根据其值所属的 bin 对数据帧的每一行进行分类?
【发布时间】:2019-05-03 10:55:39
【问题描述】:

在 R 中,我想通过对值进行分箱并使用每个箱中的值的数量(总和)通过使用 if-else 逻辑将它们分配到 2 组(类)来对数据帧的每一行进行分类。

  • 在 R for 循环中,我使用 R cut 和 split 命令将 按行排列值。
  • 分档(范围)为:1..9、10..19、20..29、30..39、40..49。
  • 如果一行包含 1 对位于同一 bin(范围)中的值, 比如说 10..19,那么它应该被归类为“P”。如果包含 2 对落入 2 个不同的箱子(范围),那么它们应该是 归类为“PP”。
  • 然后我使用硬编码创建了两个名为 p 和 pp 的新变量 条件/规则。变量中的值为 TRUE 或 FALSE,取决于第 n 行是否符合这些规则。
  • 最后,我在 if-else 语句中使用 p 和 pp 作为条件 将每一行分配给 P 类(第一行)或 PP 类(第二行)。

首先,我创建了一个数据框 x:

n1 <- c(1, 7); n2 <- c(2, 11); n3 <- c(10, 14); n4 <- c(23, 32); n5 <- c(37, 37); n6 <- c(45, 41)
x <- data.frame(n1, n2, n3, n4, n5, n6)
x
  n1 n2 n3 n4 n5 n6
1  1  2 10 23 37 45
2  7 11 14 32 37 41

第 1 行应归类为“P”,因为它有 1 对值 (1, 2) 落在同一个 bin 1..10 中。
第 2 行应归类为“PP”,因为它有 2 对值(11、14 和 32、37)分别落在 2 个 bin 中:10..19 和 30..39。

所以,在创建数据框 x 之后,我创建了一个 for 循环:

for(i in nrow(x)){

# binning the data:
  bins <- split(as.numeric(x[i, ]), cut(as.numeric(x[i, ]), c(0, 9, 19, 29, 39, 49)))
  # creating the rule for p (1 pair of numbers falling in the same range)
  p <- (sum(lengths(bins) == 2) == 1 & sum(lengths(bins) == 1) == 4)
  # creating the rule for pp (2 different pairs, each has 2 numbers falling in the same range)
  pp <- (sum(lengths(bins) == 2) == 2 & sum(lengths(bins) == 1) == 2 & sum(lengths(bins) == 0) == 1)

  if(p){
    x$types <- "P"
  } else if(pp){
    x$types <- "PP"
  } else{
    stop("error")
  }
  }

print(x)

我想创建一个名为 types 的新列,包含类 P 或 PP:

  n1 n2 n3 n4 n5 n6 types
1  1  2 10 23 37 45 P
2  7 11 14 32 37 41 PP

代码只返回 PP:

  n1 n2 n3 n4 n5 n6 types
1  1  2 10 23 37 45 PP
2  7 11 14 32 37 41 PP

这是因为循环在行上运行了两次。但是如果它只运行一次,所有的行都被归类为“P”,而不是“PP”。我希望这是非常简单的事情,只是到目前为止无法弄清楚。

【问题讨论】:

  • 也许只需使用cut 并设置labels?有理由应用循环吗?
  • for-loop 不是必须的,但是使用标签:我不知道,因为我想使用创建变量 p 和 pp 时定义的规则

标签: r for-loop if-statement grouping binning


【解决方案1】:

您的for 循环中的错误是您在分配type 时没有使用ix$types &lt;- "P" 将整个 types 列分配为 "P"x$types &lt;- "PP" 将整个 types 列分配为 "PP"。因此,无论最后的结果是什么,这将是整个列的值。

此外,在添加 types 列后,使用 整行 x[i, ] 是危险的。大概您不想尝试将types 的“P”和“PP”值转换为数字并将它们装箱。我建议将types 设为一个单独的向量,并且仅将其添加为循环之后 的列。循环前:types &lt;- chracter(nrow(x))。在循环内部:types[i] &lt;- 而不是 x$types &lt;-。循环结束后,x$types &lt;- types

当您的意思是 for (i in 1:nrow(x)) 时,您还犯了 for (i in nrow(x)) 的经典语法错误。

解决所有这些问题:

n1 <- c(1, 7); n2 <- c(2, 11); n3 <- c(10, 14); n4 <- c(23, 32); n5 <- c(37, 37); n6 <- c(45, 41)
x <- data.frame(n1, n2, n3, n4, n5, n6)

types <- character(nrow(x))

for(i in 1:nrow(x)){
  # binning the data:
  bins <- split(as.numeric(x[i, ]), cut(as.numeric(x[i, ]), c(0, 9, 19, 29, 39, 49)))
  # creating the rule for p (1 pair of numbers falling in the same range)
  p <- (sum(lengths(bins) == 2) == 1 & sum(lengths(bins) == 1) == 4)
  # creating the rule for pp (2 different pairs, each has 2 numbers falling in the same range)
  pp <- (sum(lengths(bins) == 2) == 2 & sum(lengths(bins) == 1) == 2 & sum(lengths(bins) == 0) == 1)

  if(p){
    types[i] <- "P"
  } else if(pp){
    types[i] <- "PP"
  } else{
    stop("error")
  }
}

x$types <- types
x
#   n1 n2 n3 n4 n5 n6 types
# 1  1  2 10 23 37 45     P
# 2  7 11 14 32 37 41    PP

【讨论】:

  • 感谢您指出的事情。我自己也很难弄明白。所以,现在它可以工作了。奇怪的是,我没有为简洁提供的完整代码在没有 x$types 的情况下工作得更好
【解决方案2】:

不好看

x['types'] <- apply(x, 1, function(a) {stringr::str_replace_all(paste(+(table(floor(a/10)) > 1), collapse=""), c('1'='P','0'=''))})

拆包

floor(a/10) 转换为 bin
table(...) &gt; 1 计数 bins 并为 > 1
+(...) 转换逻辑 @ 的那些返回 TRUE 987654326@ 到 1/0
paste(..., collapse="") 将字符串向量连接到没有空格的单个字符串
str_replace_all(..., c('1'='P', ...)) 使用定义为 'old'='new' 的模式替换替换所有子字符串

结果

  n1 n2 n3 n4 n5 n6 types
1  1  2 10 23 37 45     P
2  7 11 14 32 37 41    PP

【讨论】:

  • 谢谢。问题在于它不是二进制情​​况(即,如果不是 p,则不是 pp)。我的意思是,它不是:如果 x 1 这样做。我只是没有粘贴整个代码以使事情变得更简单。如代码所示,规则是硬编码的,如模板: p
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-12
  • 1970-01-01
  • 1970-01-01
  • 2022-11-30
  • 1970-01-01
相关资源
最近更新 更多