Reputation: 5069
I have a dataframe df
like below - which has the agg points gained / lost scored over several months.
name month agg_points
A 2017-04-01 1
B 2017-04-01 3
C 2017-04-01 0
A 2017-05-01 2
B 2017-05-01 5
C 2017-05-01 2
A 2017-06-01 4
B 2017-06-01 5
C 2017-06-01 1
I need to find the net points gained / lost on a per month basis - this would mean subtracting the previous month's points from current month's point. How do I go about accessing the previous month's points in df
?
expected output
name month net_points
A 2017-04-01 1
B 2017-04-01 3
C 2017-04-01 0
A 2017-05-01 1
B 2017-05-01 2
C 2017-05-01 2
A 2017-06-01 2
B 2017-06-01 0
C 2017-06-01 -1
Upvotes: 1
Views: 60
Reputation: 5673
I have the data.table equivalent of markdly answer :
library(data.table)
DT <- setDT(df)
setkey(DT,month)
x <- DT[, list(netpoint = diff(agg_points), month = .SD[-1,month]),by = name]
x is the data_table with the differences value. We then merge x and DT
DT <- x[DT, on = .(name,month)][,c("name","month","agg_points","netpoint")]
and add the first values of netpoint (equal to agg_points)
DT[,netpoint :={netpoint[1]<-agg_points[1]; netpoint},by=name]
Which gives
name month agg_points netpoint
1: A 2017-04-01 1 1
2: B 2017-04-01 3 3
3: C 2017-04-01 0 0
4: A 2017-05-01 2 1
5: B 2017-05-01 5 2
6: C 2017-05-01 2 2
7: A 2017-06-01 4 2
8: B 2017-06-01 5 0
9: C 2017-06-01 1 -1
A closer way to markdly answer would be :
DT <- setDT(df)
setkey(DT,month)
DT[,netpoint := agg_points - c(NA, agg_points[-.N]), by = name]
But I still need to do
DT[,netpoint :={netpoint[1]<-agg_points[1]; netpoint},by=name]
To fill the first rows, which desappoint me. Anyone have a better way ?
Upvotes: 0
Reputation: 733
You can create new temporary variable lag and use X3 - lag
to get net_points.
library(readr)
df <- read_csv(
"A,2017-04-01,1
B,2017-04-01,3
C,2017-04-01,0
A,2017-05-01,2
B,2017-05-01,5
C,2017-05-01,2
A,2017-06-01,4
B,2017-06-01,5
C,2017-06-01,1",
col_names = F
)
str(df)
library(dplyr)
df %>% group_by(X1) %>% mutate(lag = lag(X3), diff = ifelse(!is.na(lag), X3 - lag, X3)) %>%
select(-lag)
gives
X1 X2 X3 diff
<chr> <date> <int> <int>
1 A 2017-04-01 1 1
2 B 2017-04-01 3 3
3 C 2017-04-01 0 0
4 A 2017-05-01 2 1
5 B 2017-05-01 5 2
6 C 2017-05-01 2 2
7 A 2017-06-01 4 2
8 B 2017-06-01 5 0
9 C 2017-06-01 1 -1
Upvotes: 1
Reputation: 7839
One way:
with(df, {
x <- xtabs(agg_points ~ month + name)
x[-1, ] <- diff(x)
as.data.frame(x, responseName = 'net_points')
})
# month name net_points
#1 2017-04-01 A 1
#2 2017-05-01 A 1
#3 2017-06-01 A 2
#4 2017-04-01 B 3
#5 2017-05-01 B 2
#6 2017-06-01 B 0
#7 2017-04-01 C 0
#8 2017-05-01 C 2
#9 2017-06-01 C -1
Upvotes: 1
Reputation: 4544
With dplyr
, you could use the lag
function after you group
and arrange
the rows appropriately:
library(dplyr)
df %>%
group_by(name) %>%
arrange(month, .by_group = TRUE) %>%
mutate(net_points = agg_points - lag(agg_points, default = 0)) %>%
arrange(month)
#> # A tibble: 9 x 4
#> # Groups: name [3]
#> name month agg_points net_points
#> <chr> <chr> <int> <int>
#> 1 A 2017-04-01 1 1
#> 2 B 2017-04-01 3 3
#> 3 C 2017-04-01 0 0
#> 4 A 2017-05-01 2 1
#> 5 B 2017-05-01 5 2
#> 6 C 2017-05-01 2 2
#> 7 A 2017-06-01 4 2
#> 8 B 2017-06-01 5 0
#> 9 C 2017-06-01 1 -1
Data
df <- read.table(text = "name month agg_points
A 2017-04-01 1
B 2017-04-01 3
C 2017-04-01 0
A 2017-05-01 2
B 2017-05-01 5
C 2017-05-01 2
A 2017-06-01 4
B 2017-06-01 5
C 2017-06-01 1", header = TRUE, stringsAsFactors = FALSE)
Upvotes: 3