dplyr join 并在没有 NA 的情况下保持变量 obs
dplyr join and keeping variable obs without NA
我有一个 for
循环,它根据 tdata$me
和 10% 分位数分配投资组合。我遇到的问题是当我 运行 for
循环时,我最终只有最后一个观察年和分配的投资组合。当我回顾这些年时,我的想法是放置投资组合分配 portf
,然后将其与更大的数据集结合起来。
我的问题是如何在不将 NA
放入所有其他未知 obs 的情况下加入两个数据集,而是保持 obs 原样?
此外,是否有更好的方法来 运行 这个 for
循环与 dplyr
?这似乎是一种低效的投资组合分配方式,但我想不出其他方式。
可重现的例子:
tdata <- structure(list(cusip = c(47L, 47L, 47L, 47L, 47L, 47L, 47L, 47L,
47L, 47L, 47L, 47L, 47L, 47L, 47L, 47L, 47L, 47L, 47L, 47L),
fyear = c(1970L, 1970L, 1970L, 1970L, 1970L, 1970L, 1970L,
1970L, 1970L, 1970L, 1970L, 1970L, 1971L, 1971L, 1971L, 1971L,
1971L, 1971L, 1971L, 1971L), me = c(157,115, 45, 19, 132, 21, 147,
191, 80, 165, 32, 100, 44, 134, 104,9, 183, 163, 109, 88), month = c(6L, 6L, 6L, 6L, 6L,
6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L,
8L)), .Names = c("cusip", "fyear", "me", "month"), row.names = c(NA,
20L), class = "data.frame")
for(i in unique(tdata$fyear)){
check <- filter(tdata, month == 06 & fyear == i) ###
per <- quantile(check$me, c(.10, .20, .30, .40, .50, .60, .70, .80, .90))
check$portf[check$me < per[[1]]] <- "A"
check$portf[check$me >= per[[1]] & check$me < per[[2]]] <- "B"
check$portf[check$me >= per[[2]] & check$me < per[[3]]] <- "C"
check$portf[check$me >= per[[3]] & check$me < per[[4]]] <- "D"
check$portf[check$me >= per[[4]] & check$me < per[[5]]] <- "E"
check$portf[check$me >= per[[5]] & check$me < per[[6]]] <- "F"
check$portf[check$me >= per[[6]] & check$me < per[[7]]] <- "G"
check$portf[check$me >= per[[7]] & check$me < per[[8]]] <- "H"
check$portf[check$me >= per[[8]] & check$me < per[[9]]] <- "I"
check$portf[check$me >= per[[9]]] <- "J"
check <- select(check, cusip, fyear, portf)
testcrsp <- left_join(tdata, check, by = c("cusip", "fyear")) ######
}
更新:
一个 dplyr
解决方案,用于删除 for
循环。请注意,我删除了 length()
部分,因为我不确定如何在不重复 breaks
代码的情况下在 dplyr
上执行此操作。结果略有不同,因为它只有 returns 带有 months==6
的数据框,而不是未选择月份的所有带有 NA
的数据。
tdata3 <- tdata %>% group_by(fyear) %>%
filter(month==6) %>%
mutate(portf = cut(me, labels=LETTERS[1:10], include.lowest=TRUE, breaks=(me %>% quantile(seq(0, 1, by=0.1)) %>% unique)) %>%
as.character) %>% ungroup
原文:
这就是我认为您想要的。它不使用 dplyr
因为您不需要它来简单地对这些年进行子集化和循环。它确实使用 cut
将 me
列分位数拆分为字母因子。
tdata2 <- tdata
for (i in unique(tdata$fyear)) {
thisyear <- tdata[tdata$fyear==i & tdata$month==6,]
per <- unique(quantile(thisyear$me, seq(0, 1, by=0.1)))
factors <- cut(thisyear$me, breaks=per, labels=LETTERS[1:(length(per)-1)], include.lowest=TRUE)
tdata2$portf[tdata$fyear==i & tdata$month==6] <- as.character(factors)
}
tdata2
# cusip fyear me month portf
# 1 47 1970 157 6 I
# 2 47 1970 115 6 F
# 3 47 1970 45 6 C
# 4 47 1970 19 6 A
# 5 47 1970 132 6 G
# 6 47 1970 21 6 A
# 7 47 1970 147 6 H
# 8 47 1970 191 6 J
# 9 47 1970 80 6 D
# 10 47 1970 165 6 J
# 11 47 1970 32 6 B
# 12 47 1970 100 6 E
# 13 47 1971 44 6 B
# 14 47 1971 134 6 G
# 15 47 1971 104 6 D
# 16 47 1971 9 6 A
# 17 47 1971 183 6 J
# 18 47 1971 163 6 I
# 19 47 1971 109 6 E
# 20 47 1971 88 8 <NA>
# 0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%
# A B C D E F G H I J
请注意,必须在分位数中使用唯一性,因为您可以(它发生在您编辑数据之前)具有相等的分位数,这不会被接受为 breaks
的因素。也正因为如此,如果直接输入 1:10
.
,您应该使用 length(per)
我有一个 for
循环,它根据 tdata$me
和 10% 分位数分配投资组合。我遇到的问题是当我 运行 for
循环时,我最终只有最后一个观察年和分配的投资组合。当我回顾这些年时,我的想法是放置投资组合分配 portf
,然后将其与更大的数据集结合起来。
我的问题是如何在不将 NA
放入所有其他未知 obs 的情况下加入两个数据集,而是保持 obs 原样?
此外,是否有更好的方法来 运行 这个 for
循环与 dplyr
?这似乎是一种低效的投资组合分配方式,但我想不出其他方式。
可重现的例子:
tdata <- structure(list(cusip = c(47L, 47L, 47L, 47L, 47L, 47L, 47L, 47L,
47L, 47L, 47L, 47L, 47L, 47L, 47L, 47L, 47L, 47L, 47L, 47L),
fyear = c(1970L, 1970L, 1970L, 1970L, 1970L, 1970L, 1970L,
1970L, 1970L, 1970L, 1970L, 1970L, 1971L, 1971L, 1971L, 1971L,
1971L, 1971L, 1971L, 1971L), me = c(157,115, 45, 19, 132, 21, 147,
191, 80, 165, 32, 100, 44, 134, 104,9, 183, 163, 109, 88), month = c(6L, 6L, 6L, 6L, 6L,
6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L,
8L)), .Names = c("cusip", "fyear", "me", "month"), row.names = c(NA,
20L), class = "data.frame")
for(i in unique(tdata$fyear)){
check <- filter(tdata, month == 06 & fyear == i) ###
per <- quantile(check$me, c(.10, .20, .30, .40, .50, .60, .70, .80, .90))
check$portf[check$me < per[[1]]] <- "A"
check$portf[check$me >= per[[1]] & check$me < per[[2]]] <- "B"
check$portf[check$me >= per[[2]] & check$me < per[[3]]] <- "C"
check$portf[check$me >= per[[3]] & check$me < per[[4]]] <- "D"
check$portf[check$me >= per[[4]] & check$me < per[[5]]] <- "E"
check$portf[check$me >= per[[5]] & check$me < per[[6]]] <- "F"
check$portf[check$me >= per[[6]] & check$me < per[[7]]] <- "G"
check$portf[check$me >= per[[7]] & check$me < per[[8]]] <- "H"
check$portf[check$me >= per[[8]] & check$me < per[[9]]] <- "I"
check$portf[check$me >= per[[9]]] <- "J"
check <- select(check, cusip, fyear, portf)
testcrsp <- left_join(tdata, check, by = c("cusip", "fyear")) ######
}
更新:
一个 dplyr
解决方案,用于删除 for
循环。请注意,我删除了 length()
部分,因为我不确定如何在不重复 breaks
代码的情况下在 dplyr
上执行此操作。结果略有不同,因为它只有 returns 带有 months==6
的数据框,而不是未选择月份的所有带有 NA
的数据。
tdata3 <- tdata %>% group_by(fyear) %>%
filter(month==6) %>%
mutate(portf = cut(me, labels=LETTERS[1:10], include.lowest=TRUE, breaks=(me %>% quantile(seq(0, 1, by=0.1)) %>% unique)) %>%
as.character) %>% ungroup
原文:
这就是我认为您想要的。它不使用 dplyr
因为您不需要它来简单地对这些年进行子集化和循环。它确实使用 cut
将 me
列分位数拆分为字母因子。
tdata2 <- tdata
for (i in unique(tdata$fyear)) {
thisyear <- tdata[tdata$fyear==i & tdata$month==6,]
per <- unique(quantile(thisyear$me, seq(0, 1, by=0.1)))
factors <- cut(thisyear$me, breaks=per, labels=LETTERS[1:(length(per)-1)], include.lowest=TRUE)
tdata2$portf[tdata$fyear==i & tdata$month==6] <- as.character(factors)
}
tdata2
# cusip fyear me month portf
# 1 47 1970 157 6 I
# 2 47 1970 115 6 F
# 3 47 1970 45 6 C
# 4 47 1970 19 6 A
# 5 47 1970 132 6 G
# 6 47 1970 21 6 A
# 7 47 1970 147 6 H
# 8 47 1970 191 6 J
# 9 47 1970 80 6 D
# 10 47 1970 165 6 J
# 11 47 1970 32 6 B
# 12 47 1970 100 6 E
# 13 47 1971 44 6 B
# 14 47 1971 134 6 G
# 15 47 1971 104 6 D
# 16 47 1971 9 6 A
# 17 47 1971 183 6 J
# 18 47 1971 163 6 I
# 19 47 1971 109 6 E
# 20 47 1971 88 8 <NA>
# 0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%
# A B C D E F G H I J
请注意,必须在分位数中使用唯一性,因为您可以(它发生在您编辑数据之前)具有相等的分位数,这不会被接受为 breaks
的因素。也正因为如此,如果直接输入 1:10
.
length(per)