R:根据嵌套循环生成新列
R: Generate new columns based on nested loops
我是一名应用研究员,主要处理全国注册数据,正在从 Stata 过渡到 R。dplyr
包使我的大部分日常数据管理任务顺利进行。尽管如此,我目前正在努力让 R 生成基于嵌套循环的新变量。
假设我们有以下关于 1990-1992 年间出生的六名参与者的数据集,以及他们在 2001-2004 年间的平均绩点测量值。
* Stata
clear all
input id byear gpa2000 gpa2001 gpa2002 gpa2003 gpa2004
1 1990 1.2 1.3 1.4 1.5 1.3
2 1990 2.3 2.5 2.2 2.1 2.6
3 1991 3.1 3.9 3.4 3.5 4.0
4 1991 2.6 3.1 2.4 1.9 3.1
5 1992 1.4 1.8 3.2 2.3 3.2
6 1992 3.5 4.0 4.0 4.0 3.9
end
list
+--------------------------------------------------------------+
| id byear gpa2000 gpa2001 gpa2002 gpa2003 gpa2004 |
|--------------------------------------------------------------|
1. | 1 1990 1.2 1.3 1.4 1.5 1.3 |
2. | 2 1990 2.3 2.5 2.2 2.1 2.6 |
3. | 3 1991 3.1 3.9 3.4 3.5 4 |
4. | 4 1991 2.6 3.1 2.4 1.9 3.1 |
5. | 5 1992 1.4 1.8 3.2 2.3 3.2 |
6. | 6 1992 3.5 4 4 4 3.9 |
+--------------------------------------------------------------+
或者在 R 中等效:
df <- read.table(header=T, text="id byear gpa2000 gpa2001 gpa2002 gpa2003 gpa2004
1 1990 1.2 1.3 1.4 1.5 1.3
2 1990 2.3 2.5 2.2 2.1 2.6
3 1991 3.1 3.9 3.4 3.5 4.0
4 1991 2.6 3.1 2.4 1.9 3.1
5 1992 1.4 1.8 3.2 2.3 3.2
6 1992 3.5 4.0 4.0 4.0 3.9
")
我现在想生成三个新变量来衡量每个参与者在 10-12 岁之间的 GPA (gpa_age10 ... gpa_age12)。
在 Stata 中,我通常会通过嵌套 for 循环的方式来做到这一点:
forval i = 10/12 {
gen gpa_age`i' = .
forval j = 1990/1992 {
replace gpa_age`i' = gpa`=`j'+`i'' if byear == `j'
}
}
这将产生以下数据集:
+-----------------------------------------------------------------------------------------------+
| id byear gpa2000 gpa2001 gpa2002 gpa2003 gpa2004 gpa_a~10 gpa_a~11 gpa_a~12 |
|-----------------------------------------------------------------------------------------------|
1. | 1 1990 1.2 1.3 1.4 1.5 1.3 1.2 1.3 1.4 |
2. | 2 1990 2.3 2.5 2.2 2.1 2.6 2.3 2.5 2.2 |
3. | 3 1991 3.1 3.9 3.4 3.5 4 3.9 3.4 3.5 |
4. | 4 1991 2.6 3.1 2.4 1.9 3.1 3.1 2.4 1.9 |
5. | 5 1992 1.4 1.8 3.2 2.3 3.2 3.2 2.3 3.2 |
6. | 6 1992 3.5 4 4 4 3.9 4 4 3.9 |
+-----------------------------------------------------------------------------------------------+
我知道可能无法将此 Stata 代码直接转换为 R,但在 R 中复制这些结果的最佳方式是什么?
您可以将 data.frame 重塑为一种形式,其中每一行代表使用 reshape2
包的学生的一年。然后计算年龄变得微不足道。这是完成此任务的完整代码,假设上面的 data.frame 在一个名为 dat
:
的变量中
mdat <- melt(dat, id.vars=c('id', 'byear'), value.name='gpa')
mdat %>%
mutate(year=as.numeric(gsub('gpa', '', variable))) %>%
select(id, byear, year, gpa) %>%
mutate(age=year-byear)
此外,您可以通过铸造熔化的 data.frame:
来获得您要求的 data.frame
dcast(mdat, id + byear ~ age, value.var='gpa')
> id byear 8 9 10 11 12 13 14
> 1 1990 NA NA 1.2 1.3 1.4 1.5 1.3
> 2 1990 NA NA 2.3 2.5 2.2 2.1 2.6
> 3 1991 NA 3.1 3.9 3.4 3.5 4.0 NA
> 4 1991 NA 2.6 3.1 2.4 1.9 3.1 NA
> 5 1992 1.4 1.8 3.2 2.3 3.2 NA NA
> 6 1992 3.5 4.0 4.0 4.0 3.9 NA NA
我知道@cr1msonB1ade 已经很好地处理了这个问题,但是要向 OP 展示 R 中的嵌套 for 循环版本以匹配发布的 Stata 代码:
for (i in 10:12) {
for (j in 1990:1992) {
gpadf[[paste0("gpa_age", i)]][gpadf$byear==j] <-
gpadf[[paste0("gpa", j+i)]][gpadf$byear==j]
}
}
我是一名应用研究员,主要处理全国注册数据,正在从 Stata 过渡到 R。dplyr
包使我的大部分日常数据管理任务顺利进行。尽管如此,我目前正在努力让 R 生成基于嵌套循环的新变量。
假设我们有以下关于 1990-1992 年间出生的六名参与者的数据集,以及他们在 2001-2004 年间的平均绩点测量值。
* Stata
clear all
input id byear gpa2000 gpa2001 gpa2002 gpa2003 gpa2004
1 1990 1.2 1.3 1.4 1.5 1.3
2 1990 2.3 2.5 2.2 2.1 2.6
3 1991 3.1 3.9 3.4 3.5 4.0
4 1991 2.6 3.1 2.4 1.9 3.1
5 1992 1.4 1.8 3.2 2.3 3.2
6 1992 3.5 4.0 4.0 4.0 3.9
end
list
+--------------------------------------------------------------+
| id byear gpa2000 gpa2001 gpa2002 gpa2003 gpa2004 |
|--------------------------------------------------------------|
1. | 1 1990 1.2 1.3 1.4 1.5 1.3 |
2. | 2 1990 2.3 2.5 2.2 2.1 2.6 |
3. | 3 1991 3.1 3.9 3.4 3.5 4 |
4. | 4 1991 2.6 3.1 2.4 1.9 3.1 |
5. | 5 1992 1.4 1.8 3.2 2.3 3.2 |
6. | 6 1992 3.5 4 4 4 3.9 |
+--------------------------------------------------------------+
或者在 R 中等效:
df <- read.table(header=T, text="id byear gpa2000 gpa2001 gpa2002 gpa2003 gpa2004
1 1990 1.2 1.3 1.4 1.5 1.3
2 1990 2.3 2.5 2.2 2.1 2.6
3 1991 3.1 3.9 3.4 3.5 4.0
4 1991 2.6 3.1 2.4 1.9 3.1
5 1992 1.4 1.8 3.2 2.3 3.2
6 1992 3.5 4.0 4.0 4.0 3.9
")
我现在想生成三个新变量来衡量每个参与者在 10-12 岁之间的 GPA (gpa_age10 ... gpa_age12)。
在 Stata 中,我通常会通过嵌套 for 循环的方式来做到这一点:
forval i = 10/12 {
gen gpa_age`i' = .
forval j = 1990/1992 {
replace gpa_age`i' = gpa`=`j'+`i'' if byear == `j'
}
}
这将产生以下数据集:
+-----------------------------------------------------------------------------------------------+
| id byear gpa2000 gpa2001 gpa2002 gpa2003 gpa2004 gpa_a~10 gpa_a~11 gpa_a~12 |
|-----------------------------------------------------------------------------------------------|
1. | 1 1990 1.2 1.3 1.4 1.5 1.3 1.2 1.3 1.4 |
2. | 2 1990 2.3 2.5 2.2 2.1 2.6 2.3 2.5 2.2 |
3. | 3 1991 3.1 3.9 3.4 3.5 4 3.9 3.4 3.5 |
4. | 4 1991 2.6 3.1 2.4 1.9 3.1 3.1 2.4 1.9 |
5. | 5 1992 1.4 1.8 3.2 2.3 3.2 3.2 2.3 3.2 |
6. | 6 1992 3.5 4 4 4 3.9 4 4 3.9 |
+-----------------------------------------------------------------------------------------------+
我知道可能无法将此 Stata 代码直接转换为 R,但在 R 中复制这些结果的最佳方式是什么?
您可以将 data.frame 重塑为一种形式,其中每一行代表使用 reshape2
包的学生的一年。然后计算年龄变得微不足道。这是完成此任务的完整代码,假设上面的 data.frame 在一个名为 dat
:
mdat <- melt(dat, id.vars=c('id', 'byear'), value.name='gpa')
mdat %>%
mutate(year=as.numeric(gsub('gpa', '', variable))) %>%
select(id, byear, year, gpa) %>%
mutate(age=year-byear)
此外,您可以通过铸造熔化的 data.frame:
来获得您要求的 data.framedcast(mdat, id + byear ~ age, value.var='gpa')
> id byear 8 9 10 11 12 13 14
> 1 1990 NA NA 1.2 1.3 1.4 1.5 1.3
> 2 1990 NA NA 2.3 2.5 2.2 2.1 2.6
> 3 1991 NA 3.1 3.9 3.4 3.5 4.0 NA
> 4 1991 NA 2.6 3.1 2.4 1.9 3.1 NA
> 5 1992 1.4 1.8 3.2 2.3 3.2 NA NA
> 6 1992 3.5 4.0 4.0 4.0 3.9 NA NA
我知道@cr1msonB1ade 已经很好地处理了这个问题,但是要向 OP 展示 R 中的嵌套 for 循环版本以匹配发布的 Stata 代码:
for (i in 10:12) {
for (j in 1990:1992) {
gpadf[[paste0("gpa_age", i)]][gpadf$byear==j] <-
gpadf[[paste0("gpa", j+i)]][gpadf$byear==j]
}
}