I have a data frame
data<-data.frame(Type=c("A","B","D","D","E","E"),
Ratio=c(5,6,3,3,4,4),
Number=c(65,74,43,34,23,12),
Letter=c("P","K","M","M","N","B"),
Season=c("Fall","Spring","Winter",
"Summer","Spring","Winter"))
> data
Type Ratio Number Letter Season
A 5 65 P Fall
B 6 74 K Spring
D 3 43 M Winter
D 3 34 M Summer
E 4 23 N Spring
E 4 12 B Winter
Where I would like to add new rows to the 'Types' that are only used once(A and B). I would like to add a bow beneath each of there rows that contains the same type,ratio, and number for the one above it, but NA for letter and season. I have used
group_by(Type)
to start
I would want my final data frame to look like this
Type Ratio Number Letter Season
A 5 65 P Fall
A 5 65 NA NA
B 6 74 K Spring
B 6 74 NA NA
D 3 43 M Winter
D 3 34 M Summer
E 4 23 N Spring
E 4 12 B Winter
Thanks!
Another data.table
solution:
setDT(data)[, if (.N == 1L)
c(Number = list(Number), .SD[1:2, .(Letter, Season)])
else .SD,
by=.(Type, Ratio)]
# Type Ratio Number Letter Season
# 1: A 5 65 P Fall
# 2: A 5 65 NA NA
# 3: B 6 74 K Spring
# 4: B 6 74 NA NA
# 5: D 3 43 M Winter
# 6: D 3 34 M Summer
# 7: E 4 23 N Spring
# 8: E 4 12 B Winter
Using data.table
:
library(data.table) #1.9.5+
setDT(data)
data<-setkey(rbindlist(list(data,data[,if(.N==1).SD[,!c("Letter","Season"),with=F],by=Type]),fill=T),Type)
> data
Type Ratio Number Letter Season
1: A 5 65 P Fall
2: A 5 65 NA NA
3: B 6 74 K Spring
4: B 6 74 NA NA
5: D 3 43 M Winter
6: D 3 34 M Summer
7: E 4 23 N Spring
8: E 4 12 B Winter
Base package:
d1 <- as.data.frame(table(data$Type))
d2 <- data[data$Type %in% d1[d1$Freq<2,1], 1:3]
d2[, c("Letter", "Season")] <- NA
d3 <- rbind(data, d2)
d3[order(d3$Type), ]
Using dplyr
and base package. I've refined my solution based on the use of bind_rows
by Nick Kennedy. So I don't need to create my NA columns.
library(dplyr)
d1 <- data %>% group_by(Type) %>% summarize(count = n()) %>% filter (count<2)
d2 <- data[data$Type %in% d1$Type, 1:3]
d3 <- bind_rows(data, d2)
d3[order(d3$Type), ]
Output:
Type Ratio Number Letter Season
1 A 5 65 P Fall
7 A 5 65 <NA> <NA>
2 B 6 74 K Spring
8 B 6 74 <NA> <NA>
3 D 3 43 M Winter
4 D 3 34 M Summer
5 E 4 23 N Spring
6 E 4 12 B Winter
Here's a one-line dplyr
solution (though printed over multiple lines for clarity):
data %>%
group_by(Type) %>%
do(if(nrow(.) > 1) . else bind_rows(., select(., Type, Ratio, Number)))
And if you'd prefer nested pipes to do
:
data %>%
group_by(Type) %>%
bind_rows(.,
filter(., n() < 2) %>%
select(Type, Ratio, Number)
) %>%
arrange(Type)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.