Reputation: 71
If I have a table like this:
Sam 55
Toby 30
Fred 45
gdgv 63
Wed 19
Bill 26
....
I want to split this table to several tables based on the value(>40, (30,40), <30), which means they will look like this:
table 1:
Sam 55
Fred 45
gdgv 63
table 2:
Toby 30
table 3:
Bill 19
Wed 26
how can I do this without a for loop
?
Upvotes: 1
Views: 240
Reputation: 47300
borrowing data from @markus :
split(dat, (dat$V2 >= 30) + (dat$V2 > 40))
# $`0`
# V1 V2
# 5 Wed 19
# 6 Bill 26
#
# $`1`
# V1 V2
# 2 Toby 30
#
# $`2`
# V1 V2
# 1 Sam 55
# 3 Fred 45
# 4 gdgv 63
Upvotes: 0
Reputation: 16277
If you do not want to use the split
and cut
method from @markus, which gives a list as a result, and simply want to create 3 separate objects, you can simply do this.
df<-read.table(text="Name Number
Sam 55
Toby 30
Fred 45
gdgv 63
Wed 19
Bill 26",header=T)
table1 <- df[df$Number>40,]
table2 <- df[df$Number>=30 & df$Number<=40,]
table3 <- df[df$Number<30,]
Upvotes: 0
Reputation: 39858
With dplyr
you can try something like this:
df %>%
group_split(grp = ifelse(V2 > 40, 1,
ifelse(V2 >= 30 & V2 <= 40, 2, 3)))
[[1]]
# A tibble: 3 x 3
V1 V2 grp
<chr> <int> <dbl>
1 Sam 55 1
2 Fred 45 1
3 gdgv 63 1
[[2]]
# A tibble: 1 x 3
V1 V2 grp
<chr> <int> <dbl>
1 Toby 30 2
[[3]]
# A tibble: 2 x 3
V1 V2 grp
<chr> <int> <dbl>
1 Wed 19 3
2 Bill 26 3
Or the same idea using case_when()
instead of ifelse()
:
df %>%
group_split(grp = case_when(V2 > 40 ~ 1,
V2 >= 30 & V2 <= 40 ~ 2,
TRUE ~ 3))
Or with cut()
:
df %>%
group_split(grp = cut(V2,
breaks = c(-Inf, 30, 40, Inf),
labels = c("<30", "(30,40)", ">40"),
right = FALSE))
[[1]]
# A tibble: 2 x 3
V1 V2 grp
<chr> <int> <fct>
1 Wed 19 <30
2 Bill 26 <30
[[2]]
# A tibble: 1 x 3
V1 V2 grp
<chr> <int> <fct>
1 Toby 30 (30,40)
[[3]]
# A tibble: 3 x 3
V1 V2 grp
<chr> <int> <fct>
1 Sam 55 >40
2 Fred 45 >40
3 gdgv 63 >40
Upvotes: 3
Reputation: 13309
Using plyr
(data in Note below):
plyr::llply(split(df2,df2$Number<30),function(x) split(x,x$Number>30))
Result:
$`FALSE`
$`FALSE`$`FALSE`
Name Number
2 Toby 30
$`FALSE`$`TRUE`
Name Number
1 Sam 55
3 Fred 45
4 gdgv 63
$`TRUE`
$`TRUE`$`FALSE`
Name Number
5 Wed 19
6 Bill 26
NOTE::
df2<-read.table(text="Name Number
Sam 55
Toby 30
Fred 45
gdgv 63
Wed 19
Bill 26",header=T)
Upvotes: 0
Reputation: 26343
You can use split
and cut
split(dat,
cut(dat$V2,
breaks = c(-Inf, 30, 40, Inf),
labels = c("<30", "(30,40)", ">40"),
right = FALSE))
#$`<30`
# V1 V2
#5 Wed 19
#6 Bill 26
#$`(30,40)`
# V1 V2
#2 Toby 30
#$`>40`
# V1 V2
#1 Sam 55
#3 Fred 45
#4 gdgv 63
data
text <- "Sam 55
Toby 30
Fred 45
gdgv 63
Wed 19
Bill 26"
dat <- read.table(text = text, stringsAsFactors = FALSE, header = FALSE)
Upvotes: 5