Create a column from groupby with a calculated label

Viewed 160

I have a dataframe and I would like to create a dataframe column based on the groupby on another column. The group by should be in increments of 50 on the column and the label should be the middle number in the group numbers. I am demonstrating this here with a reproducible example.

Here is the dataframe

das <- data.frame(val=1:27,
              weigh=c(20,25,37,38,50,52,56,59,64,68,69,70,75,76,82,85,90,100,109,150,161,178,181,179,180,201,201))

    val  weigh
1     1  20
2     2  25
3     3  37
4     4  38
5     5  50
6     6  52
7     7  56
8     8  59
9     9  64
10   10  68
11   11  69
12   12  70
13   13  75
14   14  76
15   15  82
16   16  85
17   17  90
18   18 100
19   19 109
20   20 150
21   21 161
22   22 178
23   23 181
24   24 179
25   25 180
26   26 201
27   27 201

The desired output will be

    val  weigh label
1     1  20    45
2     2  25    45
3     3  37    45
4     4  38    45
5     5  50    45
6     6  52    45
7     7  56    45
8     8  59    45
9     9  64    45
10   10  68    45
11   11  69    45
12   12  70    45
13   13  75    95
14   14  76    95
15   15  82    95
16   16  85    95
17   17  90    95
18   18 100    95
19   19 109    95
20   20 150    145
21   21 161    145
22   22 178    195
23   23 181    195
24   24 179    195
25   25 180    195
26   26 201    195
27   27 201    195

Here the 45 is calculate by 20+ (20+50) /2 = 45, where 20 is where it start and 20+50 = 70 is where this group need to stop. And the label is the middle number between 20 and 70 which is 45.

Similarly with other labels

 70+(70+50)/2= 95
 120 + (170)/2= 145
 170 + (220)/2 = 195

I am new to R and tried looking at many sources here, but I couldn't find anything that will do something like this. The closest I could find is grouping like this using cut2

df %>% mutate(label = as.numeric(cut2(weigh, g=5))) 
1 Answers
library(dplyr)

# create your breaks
breaks = unique(c(seq(min(das$weigh), max(das$weigh)+1, 50), max(das$weigh)+1))

das %>%
  group_by(group = cut(weigh, breaks, right=F)) %>%        # group by intervals
  mutate(group2 = as.numeric(group),                       # use the intervals as a number
         label = (breaks[group2]+breaks[group2]+50)/2) %>% # call the corresponding break value and calculate your label
  ungroup()

# # A tibble: 27 x 5
#     val weigh group   group2 label
#   <int> <dbl> <fct>    <dbl> <dbl>
# 1     1    20 [20,70)      1    45
# 2     2    25 [20,70)      1    45
# 3     3    37 [20,70)      1    45
# 4     4    38 [20,70)      1    45
# 5     5    50 [20,70)      1    45
# 6     6    52 [20,70)      1    45
# 7     7    56 [20,70)      1    45
# 8     8    59 [20,70)      1    45
# 9     9    64 [20,70)      1    45
#10    10    68 [20,70)      1    45
# # ... with 17 more rows

You can remove any unnecessary columns. I left them there just to make easier to understand how the process works.

Related