遍历列并为每个记录生成行 R

loop through columns and generate rows for each record R

当我以前在 SAS 中编程时,很容易在变量之间循环并在应用某种逻辑后生成行。我想在 R 中执行此操作。为了说明,请考虑以下场景。

Input
+----+----------------+-------------------+-------------+
| ID |      lvl1      |        lvl2       |     lvl3    |
+----+----------------+-------------------+-------------+
|  1 |  United States |  Ohio             |  Cincinnati |
|  2 |  Ohio          |  Cincinnati       |             |
|  3 |  Canada        |  British Columbia |  Vancouver  |
+----+----------------+-------------------+-------------+

令数组 _lvl 包含 lvl1、lvl2 和 lvl3,并从 i = 1 到 3(上限)循环。

  1. 循环 1:_lvl(1) 检查 lvl1 是否为空,如果不是则输出,为其他值提供空值。
  2. 循环 2:_lvl(2) 检查 lvl1 是否为 null 或 lvl2 是否为 null,如果不是则输出,为 lvl3 提供 null。
  3. 循环3:_lvl(3)检查lvl1是否为null,lvl2是否为null,lvl3是否为null,否则输出。

这应该为 ID = 2 生成以下内容。

Output
+----+-------+-------------+-------+
| ID |  lvl1 |     lvl2    |  lvl3 |
+----+-------+-------------+-------+
|  2 |  Ohio |             |       |
|  2 |  Ohio |  Cincinnati |       |
+----+-------+-------------+-------+

提前谢谢你。

这是使用一些索引在适当的地方清空值的一种尝试:

newdat <- dat[rep(1:nrow(dat),each=3),]
newdat[-1][upper.tri(dat[-1])[rep(1:nrow(dat),3),]] <- ""
unique(newdat)

#    ID          lvl1             lvl2       lvl3
#1    1 United States                            
#1.1  1 United States             Ohio           
#1.2  1 United States             Ohio Cincinnati
#2    2          Ohio                            
#2.1  2          Ohio       Cincinnati           
#3    3        Canada                            
#3.1  3        Canada British Columbia           
#3.2  3        Canada British Columbia  Vancouver

这是可行的,因为创建的矩阵指示要删除 newdat:

的哪些部分
upper.tri(dat[-1])[rep(1:nrow(dat),3),]
#       [,1]  [,2]  [,3]
# [1,] FALSE  TRUE  TRUE
# [2,] FALSE FALSE  TRUE
# [3,] FALSE FALSE FALSE
# [4,] FALSE  TRUE  TRUE
# [5,] FALSE FALSE  TRUE
# [6,] FALSE FALSE FALSE
# [7,] FALSE  TRUE  TRUE
# [8,] FALSE FALSE  TRUE
# [9,] FALSE FALSE FALSE

其中 dat 是:

dat <- read.csv(text="ID,lvl1,lvl2,lvl3    
1,United States,Ohio,Cincinnati
2,Ohio,Cincinnati,
3,Canada,British Columbia,Vancouver", stringsAsFactors=FALSE)

我不太喜欢你的特定用例,但我对以这种方式使用 SAS 数据步骤后调整到 R 的普遍困难表示同情。

我在 R 的数据步骤中模拟输出语句的方法是沿着数据框的行(或在本例中为列)应用函数。

定义您的 "array" 列名称:

lvl <- c('lvl1','lvl2','lvl3')

然后使用函数模拟 SAS 输出语句(i 扮演与 SAS 数组索引相同的角色,data 代表输入数据帧,names是要迭代的列名称的整个向量):

outputcriteria <- function(i, data, names) {
  data <- data[!is.na(data[,names[i]]),] #exclude rows with NA in the current column
  data[,names[-(1:i)]] <- NA             #blank out columns after the current column
  return (data)
}

然后通过将输入向量设置为 1:length(lvl)(列名向量的索引)并将dataname 函数参数:

l <- lapply(1:length(lvl), outputcriteria, data = df, names = lvl)

结果l是一个包含三个数据框的列表(每次迭代一个),您可以rbind将其合并为一个数据框:

do.call(rbind, l)

主要区别在于您最终读取数据三次并每次输出一个数据帧,而不是在 SAS 中读取一次。