I have a huge data.frame like this.
First, how can I add a new column "date1" into this data.frame so that column counts the number of the UNIQUE different day in this data.frame then arranged in ascending order in that newly created column.
Second, how can I add another column "date2" into this data.frame so that column counts total different id in a day?
year month day id
2011 1 5 31
2011 1 14 22
2011 2 6 28
2011 2 17 41
2011 3 9 55
2011 1 5 34
2011 1 14 25
2011 2 6 36
2011 2 17 11
2011 3 12 10
The result I expect looks like this. Please help!
year month day id date1 date2
2011 1 5 31 1 2
2011 1 14 22 2 2
2011 2 6 28 3 2
2011 2 17 41 4 2
2011 3 9 55 5 1
2011 1 5 34 1 2
2011 1 14 25 2 2
2011 2 6 36 3 2
2011 2 17 11 4 2
2011 3 12 10 6 1
We can first combine year
, month
and day
into one column using unite
and give a unique number to each group of that combination, then group_by
same combination and count the unique id
for each combination using n_distinct
.
library(dplyr)
library(tidyr)
df %>%
unite(date, year, month, day, sep = "-", remove = FALSE) %>%
mutate(date1 = as.integer(factor(date,level = unique(date)))) %>%
group_by(date) %>%
mutate(date2 = n_distinct(id)) %>%
ungroup() %>%
select(-date)
# year month day id date1 date2
# <int> <int> <int> <int> <int> <int>
# 1 2011 1 5 31 1 2
# 2 2011 1 14 22 2 2
# 3 2011 2 6 28 3 2
# 4 2011 2 17 41 4 2
# 5 2011 3 9 55 5 1
# 6 2011 1 5 34 1 2
# 7 2011 1 14 25 2 2
# 8 2011 2 6 36 3 2
# 9 2011 2 17 11 4 2
#10 2011 3 12 10 6 1
We can do this more compactly in tidyverse
by getting the group_indices
of 'year', 'month', 'day' in the group_by
and then create the 'date2' as the number of distinct elements of 'id' ( n_distinct
)
librarytidyverse)
df1 %>%
group_by(date1 = group_indices(., year, month, day)) %>%
mutate(date2 = n_distinct(id))
# A tibble: 10 x 6
# Groups: date1 [6]
# year month day id date1 date2
# <int> <int> <int> <int> <int> <int>
# 1 2011 1 5 31 1 2
# 2 2011 1 14 22 2 2
# 3 2011 2 6 28 3 2
# 4 2011 2 17 41 4 2
# 5 2011 3 9 55 5 1
# 6 2011 1 5 34 1 2
# 7 2011 1 14 25 2 2
# 8 2011 2 6 36 3 2
# 9 2011 2 17 11 4 2
#10 2011 3 12 10 6 1
Or another compact option with data.table
(using the same logic)
library(data.table)
setDT(df1)[, date1 := .GRP, .(year, month, day)][, date2 := uniqueN(id), date1][]
# year month day id date1 date2
# 1: 2011 1 5 31 1 2
# 2: 2011 1 14 22 2 2
# 3: 2011 2 6 28 3 2
# 4: 2011 2 17 41 4 2
# 5: 2011 3 9 55 5 1
# 6: 2011 1 5 34 1 2
# 7: 2011 1 14 25 2 2
# 8: 2011 2 6 36 3 2
# 9: 2011 2 17 11 4 2
#10: 2011 3 12 10 6 1
Or this can be done with interaction
and ave
from base R
df1$date1 <- with(df1, as.integer(interaction(year, month, day,
drop = TRUE, lex.order = TRUE)))
df1$date2 <- with(df1, ave(id, date1, FUN = function(x) length(unique(x))))
df1 <- structure(list(year = c(2011L, 2011L, 2011L, 2011L, 2011L, 2011L,
2011L, 2011L, 2011L, 2011L), month = c(1L, 1L, 2L, 2L, 3L, 1L,
1L, 2L, 2L, 3L), day = c(5L, 14L, 6L, 17L, 9L, 5L, 14L, 6L, 17L,
12L), id = c(31L, 22L, 28L, 41L, 55L, 34L, 25L, 36L, 11L, 10L
)), class = "data.frame", row.names = c(NA, -10L))
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.