遍历列并为每个记录生成行 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:_lvl(1) 检查 lvl1 是否为空,如果不是则输出,为其他值提供空值。
- 循环 2:_lvl(2) 检查 lvl1 是否为 null 或 lvl2 是否为 null,如果不是则输出,为 lvl3 提供 null。
- 循环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)
(列名向量的索引)并将data
和 name
函数参数:
l <- lapply(1:length(lvl), outputcriteria, data = df, names = lvl)
结果l
是一个包含三个数据框的列表(每次迭代一个),您可以rbind
将其合并为一个数据框:
do.call(rbind, l)
主要区别在于您最终读取数据三次并每次输出一个数据帧,而不是在 SAS 中读取一次。
当我以前在 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:_lvl(1) 检查 lvl1 是否为空,如果不是则输出,为其他值提供空值。
- 循环 2:_lvl(2) 检查 lvl1 是否为 null 或 lvl2 是否为 null,如果不是则输出,为 lvl3 提供 null。
- 循环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)
(列名向量的索引)并将data
和 name
函数参数:
l <- lapply(1:length(lvl), outputcriteria, data = df, names = lvl)
结果l
是一个包含三个数据框的列表(每次迭代一个),您可以rbind
将其合并为一个数据框:
do.call(rbind, l)
主要区别在于您最终读取数据三次并每次输出一个数据帧,而不是在 SAS 中读取一次。