使用 r 中的粘贴嵌套 for 循环
Nested for loop using paste in r
我有一个包含多个 yes/no 列的数据集,这些列指示特定记录是否与三个不同区域中的给定商店编号相关联(即,一条记录对于其中一个区域具有单个是值三个地区各有两家商店,其中变量名称的格式为 'region'_'storenumber'):
var1_1 var1_2 var2_1 var2_2 var3_1 var3_2
1 Yes No No Yes Yes No
2 No Yes Yes No No Yes
3 No Yes Yes No No Yes
4 No Yes No Yes Yes No
5 No Yes No Yes No Yes
6 Yes No No Yes No Yes
7 Yes No Yes No Yes No
8 No Yes Yes No No Yes
我想为每个名为 'region_1'、'region_2' 和 'region_3' 的区域创建一个变量,该变量等于该区域中的 "Yes" 商店编号对于该记录(1 或 2):
region_1 region_2 region_3
1 1 2 1
2 2 1 2
3 2 1 2
4 2 2 1
5 2 2 2
6 1 2 2
7 1 1 1
8 2 1 2
我能够使用 for 循环分别创建每个区域变量,如下所示:
for(i in 1:3) {
df[paste("region_", toString(i), sep = "")] <- ""
}
for(i in 1:2) {
df$region_1 <- ifelse(df[paste("var1_", toString(i), sep = "")] == "Yes" & df$region_1 == "", toString(i), df$region_1)
}
for(i in 1:2) {
df_1$region_2 <- ifelse(df_1[paste("var2_", toString(i), sep = "")] == "Yes" & df_1$region_2 == "", toString(i), df_1$region_2)
}
for(i in 1:2) {
df_1$region_3 <- ifelse(df_1[paste("var3_", toString(i), sep = "")] == "Yes" & df_1$region_3 == "", toString(i), df_1$region_3)
}
我的实际数据有 3 个以上的区域(每个区域有 2 个以上的商店),所以我不想为每个区域编写一个单独的循环,而是嵌套这个循环以遍历所有区域。我尝试了以下操作:
for(j in 1:3) {
for(i in 1:2) {
df[paste("region_", toString(j), sep = "")] <- ifelse(df[paste("var", toString(j), "_", toString(i), sep = "")] == "Yes" & df[paste("region_", toString(j), sep = "")] == "", toString(i), df[paste("region_", toString(j), sep = "")])
}
}
但收到警告 "provided #### variables to replace 1 variables" 并最终为每个区域变量填充了每条记录的相同单个值。
有没有想过我的嵌套循环哪里出了问题?
如果我们将 Yes 和 No 转换为逻辑值,我们可以简单地做
regions = as.data.frame( sapply(seq(1, NCOL(stores), by=2),function(j) ifelse(stores[,j],1,2)))
names(regions) = c("region_1", "region_2", "region_3")
regions
# region_1 region_2 region_3
#1 1 2 1
#2 2 1 2
#3 2 1 2
#4 2 2 1
#5 2 2 2
#6 1 2 2
#7 1 1 1
#8 2 1 2
数据:
library(data.table)
stores = setDF(fread(gsub("No", "FALSE", gsub("Yes", "TRUE",
"var1_1 var1_2 var2_1 var2_2 var3_1 var3_2
Yes No No Yes Yes No
No Yes Yes No No Yes
No Yes Yes No No Yes
No Yes No Yes Yes No
No Yes No Yes No Yes
Yes No No Yes No Yes
Yes No Yes No Yes No
No Yes Yes No No Yes"))))
为此,您最好将数据转换为 "long" 格式,而不是当前的 "wide" 格式。以下是使用 dplyr
和 tidyr
的示例。我试图对每一行进行评论,但基本思想是为每个存储变量度量生成一行,并且只显示 presence/absence 。然后,您可以按地区对行进行分组,并计算 "Yes" 个条目的数量。
# Data entry from @dww, without conversion to logical (though that would make it easier)
library(data.table)
stores = setDF(fread("var1_1 var1_2 var2_1 var2_2 var3_1 var3_2
Yes No No Yes Yes No
No Yes Yes No No Yes
No Yes Yes No No Yes
No Yes No Yes Yes No
No Yes No Yes No Yes
Yes No No Yes No Yes
Yes No Yes No Yes No
No Yes Yes No No Yes"))
更改为长格式,存储为新变量
longStores <-
stores %>%
# tag for printing
tbl_df() %>%
# Store the variable of interest as a column, instead of row.names
mutate(variableInterest = rownames(.)) %>%
# Convert the data to long format
gather(StoreID, present, -variableInterest) %>%
# Split the store_region format
separate(StoreID, c("Store", "Region"), sep = "_") %>%
# Eliminate the leading "var" from store names, just for display
mutate(Store = gsub("var", "", Store))
按区域汇总,仍为长格式
longRegional <-
longStores %>%
# Set grouping
group_by(variableInterest, Region) %>%
# Count the number of correct values in the region
summarise(nStoresWithVariable = sum(present == "Yes"))
最后,重新格式化为您的原始请求
longRegional %>%
spread(Region, nStoresWithVariable)
# variableInterest `1` `2`
# * <chr> <int> <int>
# 1 1 2 1
# 2 2 1 2
# 3 3 1 2
# 4 4 1 2
# 5 5 0 3
# 6 6 1 2
# 7 7 3 0
# 8 8 1 2
这是我将您的数据模拟为 True 和 False 的混乱尝试:
模拟数据 - 使用随机布尔值
生成数据table
rb <- function()
{
sample(c(T,F), size=10, replace=TRUE, prob=c(0.5, 0.5) )
}
var1_1 = rb()
var2_1 = rb()
var3_1 = rb()
df <- data.frame( var1_1, !var1_1,
var2_1, !var2_1,
var3_1, !var3_1)
colnames(df) = c('var1_1', 'var1_2', 'var2_1', 'var2_2', 'var3_1', 'var3_2')
df
var1_1 var1_2 var2_1 var2_2 var3_1 var3_2
1 FALSE TRUE TRUE FALSE FALSE TRUE
2 FALSE TRUE FALSE TRUE FALSE TRUE
3 FALSE TRUE TRUE FALSE TRUE FALSE
4 FALSE TRUE TRUE FALSE FALSE TRUE
5 FALSE TRUE FALSE TRUE TRUE FALSE
6 FALSE TRUE FALSE TRUE TRUE FALSE
7 TRUE FALSE TRUE FALSE TRUE FALSE
8 TRUE FALSE FALSE TRUE TRUE FALSE
9 TRUE FALSE FALSE TRUE TRUE FALSE
10 FALSE TRUE FALSE TRUE TRUE FALSE
解决方案
cn <- names(df)
cnprefixes <- gsub("_.*?$","",cn)
cnsuffixes <- gsub("^.*?_","",cn)
newblock<-data.frame()
bFirstTime<-T
for (prefix in unique(cnprefixes))
{
block<-df[ , grepl( prefix , names( df ) ) ]
theseSuffixes <- cnsuffixes[startsWith(cn, prefix)]
j <- 1
for(suffix in theseSuffixes)
{
block[,j][block[,j]==T]=as.numeric(suffix)
j<-j+1
}
tempblock=data.frame(rowSums(block))
colnames(tempblock)<- prefix
if (bFirstTime){
newblock <- tempblock
bFirstTime <- F
}
else{
newblock<-cbind(newblock, tempblock)
}
}
新区块
var1 var2 var3
1 2 1 2
2 2 2 2
3 2 1 1
4 2 1 2
5 2 2 1
6 2 2 1
7 1 1 1
8 1 2 1
9 1 2 1
10 2 2 1
我有一个包含多个 yes/no 列的数据集,这些列指示特定记录是否与三个不同区域中的给定商店编号相关联(即,一条记录对于其中一个区域具有单个是值三个地区各有两家商店,其中变量名称的格式为 'region'_'storenumber'):
var1_1 var1_2 var2_1 var2_2 var3_1 var3_2
1 Yes No No Yes Yes No
2 No Yes Yes No No Yes
3 No Yes Yes No No Yes
4 No Yes No Yes Yes No
5 No Yes No Yes No Yes
6 Yes No No Yes No Yes
7 Yes No Yes No Yes No
8 No Yes Yes No No Yes
我想为每个名为 'region_1'、'region_2' 和 'region_3' 的区域创建一个变量,该变量等于该区域中的 "Yes" 商店编号对于该记录(1 或 2):
region_1 region_2 region_3
1 1 2 1
2 2 1 2
3 2 1 2
4 2 2 1
5 2 2 2
6 1 2 2
7 1 1 1
8 2 1 2
我能够使用 for 循环分别创建每个区域变量,如下所示:
for(i in 1:3) {
df[paste("region_", toString(i), sep = "")] <- ""
}
for(i in 1:2) {
df$region_1 <- ifelse(df[paste("var1_", toString(i), sep = "")] == "Yes" & df$region_1 == "", toString(i), df$region_1)
}
for(i in 1:2) {
df_1$region_2 <- ifelse(df_1[paste("var2_", toString(i), sep = "")] == "Yes" & df_1$region_2 == "", toString(i), df_1$region_2)
}
for(i in 1:2) {
df_1$region_3 <- ifelse(df_1[paste("var3_", toString(i), sep = "")] == "Yes" & df_1$region_3 == "", toString(i), df_1$region_3)
}
我的实际数据有 3 个以上的区域(每个区域有 2 个以上的商店),所以我不想为每个区域编写一个单独的循环,而是嵌套这个循环以遍历所有区域。我尝试了以下操作:
for(j in 1:3) {
for(i in 1:2) {
df[paste("region_", toString(j), sep = "")] <- ifelse(df[paste("var", toString(j), "_", toString(i), sep = "")] == "Yes" & df[paste("region_", toString(j), sep = "")] == "", toString(i), df[paste("region_", toString(j), sep = "")])
}
}
但收到警告 "provided #### variables to replace 1 variables" 并最终为每个区域变量填充了每条记录的相同单个值。
有没有想过我的嵌套循环哪里出了问题?
如果我们将 Yes 和 No 转换为逻辑值,我们可以简单地做
regions = as.data.frame( sapply(seq(1, NCOL(stores), by=2),function(j) ifelse(stores[,j],1,2)))
names(regions) = c("region_1", "region_2", "region_3")
regions
# region_1 region_2 region_3
#1 1 2 1
#2 2 1 2
#3 2 1 2
#4 2 2 1
#5 2 2 2
#6 1 2 2
#7 1 1 1
#8 2 1 2
数据:
library(data.table)
stores = setDF(fread(gsub("No", "FALSE", gsub("Yes", "TRUE",
"var1_1 var1_2 var2_1 var2_2 var3_1 var3_2
Yes No No Yes Yes No
No Yes Yes No No Yes
No Yes Yes No No Yes
No Yes No Yes Yes No
No Yes No Yes No Yes
Yes No No Yes No Yes
Yes No Yes No Yes No
No Yes Yes No No Yes"))))
为此,您最好将数据转换为 "long" 格式,而不是当前的 "wide" 格式。以下是使用 dplyr
和 tidyr
的示例。我试图对每一行进行评论,但基本思想是为每个存储变量度量生成一行,并且只显示 presence/absence 。然后,您可以按地区对行进行分组,并计算 "Yes" 个条目的数量。
# Data entry from @dww, without conversion to logical (though that would make it easier)
library(data.table)
stores = setDF(fread("var1_1 var1_2 var2_1 var2_2 var3_1 var3_2
Yes No No Yes Yes No
No Yes Yes No No Yes
No Yes Yes No No Yes
No Yes No Yes Yes No
No Yes No Yes No Yes
Yes No No Yes No Yes
Yes No Yes No Yes No
No Yes Yes No No Yes"))
更改为长格式,存储为新变量
longStores <-
stores %>%
# tag for printing
tbl_df() %>%
# Store the variable of interest as a column, instead of row.names
mutate(variableInterest = rownames(.)) %>%
# Convert the data to long format
gather(StoreID, present, -variableInterest) %>%
# Split the store_region format
separate(StoreID, c("Store", "Region"), sep = "_") %>%
# Eliminate the leading "var" from store names, just for display
mutate(Store = gsub("var", "", Store))
按区域汇总,仍为长格式
longRegional <-
longStores %>%
# Set grouping
group_by(variableInterest, Region) %>%
# Count the number of correct values in the region
summarise(nStoresWithVariable = sum(present == "Yes"))
最后,重新格式化为您的原始请求
longRegional %>%
spread(Region, nStoresWithVariable)
# variableInterest `1` `2`
# * <chr> <int> <int>
# 1 1 2 1
# 2 2 1 2
# 3 3 1 2
# 4 4 1 2
# 5 5 0 3
# 6 6 1 2
# 7 7 3 0
# 8 8 1 2
这是我将您的数据模拟为 True 和 False 的混乱尝试:
模拟数据 - 使用随机布尔值
生成数据tablerb <- function()
{
sample(c(T,F), size=10, replace=TRUE, prob=c(0.5, 0.5) )
}
var1_1 = rb()
var2_1 = rb()
var3_1 = rb()
df <- data.frame( var1_1, !var1_1,
var2_1, !var2_1,
var3_1, !var3_1)
colnames(df) = c('var1_1', 'var1_2', 'var2_1', 'var2_2', 'var3_1', 'var3_2')
df
var1_1 var1_2 var2_1 var2_2 var3_1 var3_2
1 FALSE TRUE TRUE FALSE FALSE TRUE
2 FALSE TRUE FALSE TRUE FALSE TRUE
3 FALSE TRUE TRUE FALSE TRUE FALSE
4 FALSE TRUE TRUE FALSE FALSE TRUE
5 FALSE TRUE FALSE TRUE TRUE FALSE
6 FALSE TRUE FALSE TRUE TRUE FALSE
7 TRUE FALSE TRUE FALSE TRUE FALSE
8 TRUE FALSE FALSE TRUE TRUE FALSE
9 TRUE FALSE FALSE TRUE TRUE FALSE
10 FALSE TRUE FALSE TRUE TRUE FALSE
解决方案
cn <- names(df)
cnprefixes <- gsub("_.*?$","",cn)
cnsuffixes <- gsub("^.*?_","",cn)
newblock<-data.frame()
bFirstTime<-T
for (prefix in unique(cnprefixes))
{
block<-df[ , grepl( prefix , names( df ) ) ]
theseSuffixes <- cnsuffixes[startsWith(cn, prefix)]
j <- 1
for(suffix in theseSuffixes)
{
block[,j][block[,j]==T]=as.numeric(suffix)
j<-j+1
}
tempblock=data.frame(rowSums(block))
colnames(tempblock)<- prefix
if (bFirstTime){
newblock <- tempblock
bFirstTime <- F
}
else{
newblock<-cbind(newblock, tempblock)
}
}
新区块
var1 var2 var3
1 2 1 2
2 2 2 2
3 2 1 1
4 2 1 2
5 2 2 1
6 2 2 1
7 1 1 1
8 1 2 1
9 1 2 1
10 2 2 1