我有一个数据集,按年填充了一堆国家的数据。我需要为某些地区(如比利时 - 卢森堡)创建数据,方法是为其他一些国家(在本例中为比利时和卢森堡)添加或以其他方式操纵数据,并将结果值填入该地区的相应年份。
例如,比方说我有比利时(BEL)和卢森堡(LUX)2001 - 2010年的数据。我需要能够说,添加,BEL-2001和LUX-2001来创建BLX-2001。数据集的列为iso(国家代码 - BEL,LUX,BLX等),年份和VARIABLE。它已经具有BEL,LUX和BLX所需的所有行(当然,在我们填充它之前BLX是空的)。
示例DATAFRAME将是:
iso year colname
BEL 1990 NA
BEL 1991 10
BEL 1992 20
BEL 1993 30
BEL 1994 10
a few rows of other countries we don't care for in this case
LUX 1990 5
LUX 1991 3
LUX 1992 NA
LUX 1993 7
LUX 1994 3
a few rows of other countries we don't care for in this case
BLX 1990 NA
BLX 1991 NA
BLX 1992 NA
BLX 1993 NA
BLX 1994 NA
在上述情况下,我们将仅填充1991,1992和1994年的BLX数据(添加BEL和LUX值) - 因为这些是BEL和LUX都具有所需数据的唯一年份。这会给我们:
iso year colname
BEL 1990 NA
BEL 1991 10
BEL 1992 20
BEL 1993 30
BEL 1994 10
a few rows of other countries we don't care for in this case
LUX 1990 5
LUX 1991 3
LUX 1992 NA
LUX 1993 7
LUX 1994 3
a few rows of other countries we don't care for in this case
BLX 1990 NA
BLX 1991 13
BLX 1992 NA
BLX 1993 37
BLX 1994 13
目前,我正在使用dplyr实现此功能,该功能采用列名称并简单地添加每个可用年份的值。这是最简单的例子,更复杂的操作看起来更加混乱:
BLXCalc <- function(colname){
LUXData <- filter(DATAFRAME, iso == "LUX" & !is.na(get(colname, envir=as.environment(DATAFRAME)))) # get only those LUX and BEL rows that have the reqd data
BELData <- filter(DATAFRAME, iso == "BEL" & !is.na(get(colname, envir=as.environment(DATAFRAME))))
BLXrange <- grep("BLX", DATAFRAME$iso) # get all BLX rows
ifelse(length(LUXData$year)<length(BELData$year), BLXyears <- LUXData$year, BLXyears <- BELData$year) # use the shorter list for the for loop
for(i in 1:length(BLXyears)){
BLXcurrentyear <- filter(DATAFRAME, iso == "LUX" & year == BLXyears[i])[[colname]] + filter(DATAFRAME, iso == "BEL" & year == BLXyears[i])[[colname]]
BLXrow <- match("BLX", DATAFRAME$iso) + match(BLXyears[i], DATAFRAME$year[BLXrange[1]:BLXrange[length(BLXrange)]]) - 1 # find the corresponding year in BLX
DATAFRAME[[colname]][BLXrow] <<- BLXcurrentyear
}
}
即使是这样一个简单的操作(添加),这也是一个混乱的代码,并不是很容易阅读。我正在做的基本细分是:
步骤3,4,5循环可用年份直到我们完成。
这适用于我们正在使用的数据,但我知道循环不是使用R的最佳方式。还有其他更多的“R”方法来实现同样的功能吗?对于较大的数据集,可能会更快,并且总体上更容易阅读。
答案 0 :(得分:2)
这是一个可能的解决方案。您首先在国家/地区拆分并创建一个列表,其中每个国家/地区都是不同的元素。使用Reduce
,您可以按名称合并任意数量的元素(function(...)
)。最后,使用rowSums
而不删除NA以添加所需的变量。如果您引用函数(fill_countries
),则可以将结果分配给感兴趣的数据子集(再次按名称指定子集)。
l1 <- split(df, df$iso)
d1 <- Reduce(function(...)merge(..., by = 'year'), l1[names(l1) %in% c('BEL', 'LUX')])
rowSums(d1[grepl('colname', names(d1))])
#[1] NA 13 NA 37 13
你也可以把它变成一个功能,
fill_countries <- function(df, country_to_fill, countries_to_use){
l1 <- split(df, df$iso)
d1 <- Reduce(function(...)merge(..., by = 'year'), l1[names(l1) %in% countries_to_use])
df$colname[df$iso == country_to_fill] <- rowSums(d1[grepl('colname', names(d1))])
return(df)
}
fill_countries(df, 'BLX', c('BEL', 'LUX'))
# iso year colname
#1 BEL 1990 NA
#2 BEL 1991 10
#3 BEL 1992 20
#4 BEL 1993 30
#5 BEL 1994 10
#6 LUX 1990 5
#7 LUX 1991 3
#8 LUX 1992 NA
#9 LUX 1993 7
#10 LUX 1994 3
#11 BLX 1990 NA
#12 BLX 1991 13
#13 BLX 1992 NA
#14 BLX 1993 37
#15 BLX 1994 13
答案 1 :(得分:0)
使用data.table
,这可以通过“单行”来解决:
library(data.table) # CRAN version 1.10.4 used
# select countries, aggregate by year,
# finally, append resulting rows to original data.frame
rbind(DF, setDT(DF)[iso %in% c("BEL", "LUX"),
.(iso = "BLX", colname = sum(colname)), by = year])
返回:
OP表示,他需要将几个地区联合起来,而不仅仅是比利时和卢森堡。上述代码可以嵌入到iso year colname 1: BEL 1990 NA 2: BEL 1991 10 3: BEL 1992 20 4: BEL 1993 30 5: BEL 1994 10 6: LUX 1990 5 7: LUX 1991 3 8: LUX 1992 NA 9: LUX 1993 7 10: LUX 1994 3 11: BLX 1990 NA 12: BLX 1991 13 13: BLX 1992 NA 14: BLX 1993 37 15: BLX 1994 13
lapply()
的调用中,以便同时组合多个区域:
# define countries and names of regions
map <- list(
BLX = c("BEL", "LUX"),
BNL = c("BEL", "NLD", "LUX"), # BeNeLux countries
IBE = c("AND", "ESP", "GIB", "PRT") # Iberian peninsula
)
# aggregate regions and add to original data set
setDT(DF)
rbindlist(c(
list(DF),
lapply(seq_along(map), function(i)
DF[iso %in% map[[i]], .(iso = names(map)[i], colname = sum(colname)), by = year]
)), use.names = TRUE)
请注意,索引号i
用于访问map
中的名称。 lapply()
会返回data.table
个对象的列表,因此rbindlist()
用于将所有对象追加,但我们需要明确设置use.names = TRUE
。
iso year colname 1: BEL 1990 NA 2: BEL 1991 10 3: BEL 1992 20 4: BEL 1993 30 5: BEL 1994 10 6: LUX 1990 5 7: LUX 1991 3 8: LUX 1992 NA 9: LUX 1993 7 10: LUX 1994 3 11: BLX 1990 NA 12: BLX 1991 13 13: BLX 1992 NA 14: BLX 1993 37 15: BLX 1994 13 16: BNL 1990 NA 17: BNL 1991 13 18: BNL 1992 NA 19: BNL 1993 37 20: BNL 1994 13