Рассчитать разницу между несколькими значениями, принадлежащими группе - PullRequest
0 голосов
/ 12 марта 2019

Я немного застрял в конкретной проблеме в R, для которой у меня есть только многословное и нелегкое решение. Может быть, кто-то знает лучший способ сделать это. Допустим, у нас есть такой фрейм данных:

x <- c("A", "B", "C", "B", "A", "C", "C", "B", "A", "B", "A", "C")
z <- c(1, 1, 1, 2, 2, 2,3, 3, 3, 4, 4,4)
y <- c(43, 32, 45, 32, 22, 52, 23, 13, 12, 4, 12, 5)
df <- data.frame(x,z,y)

с данными, похожими на это: сюжет

Я пытаюсь вычислить разницу между значениями y в группах x в зависимости от z. Например. разница между А группы 1 и А группы 2 (43-22 = 21) и А группы 2 и А группы 3 (22-12 = 10) и так далее. Я могу сделать это очень уродливо, как это:

ordered.df<-df[order(df$z, df$x),]
bl<-ordered.df[ordered.df$z==1,]
bl2<-ordered.df[ordered.df$z==2,]
bl3<-ordered.df[ordered.df$z==3,]
bl4<-ordered.df[ordered.df$z==4,]

first <- bl$y - bl2$y
second <- bl2$y - bl3$y
third <- bl3$y - bl4$y
ycolumn <- c(first,second,third)
xcolumn <- rep(c("A","B","C"),3)
zcolumn <- rep(1:3,each=3)
final.df <- data.frame(xcolumn,zcolumn,ycolumn)

и задавался вопросом, есть ли еще какие-нибудь элегантные и масштабируемые решения.

В конечном счете, я хочу сосчитать случаи положительных различий:

final.df$lower <- 0
final.df$lower[final.df$ycolumn>0] <- 1
aggregate(lower ~ zcolumn, final.df, sum)

Любые предложения приветствуются! Спасибо!

Ответы [ 3 ]

2 голосов
/ 12 марта 2019

Вот таблица данных с одной строкой

setDT(df)[, list(z = z, y_diff = y - shift(y, 1, type = "lead")), by = .(x = x)][ y_diff > 0, list(lower = .N), by = "z"]

#   z lower
#1: 1     1
#2: 2     3
#3: 3     2

что она делает:
setDT(df)
делает таблицу данных из df

[, list(z = z, y_diff = y - shift(y, 1, type = "lead")), by = .(x = x)]
сгруппировать по x, вычесть следующий y из текущего y и создать столбец y_diff с результатом

[ y_diff > 0, list(lower = .N), by = "z"]
для всех строк, где y_diff больше 0укажите количество строк (= .N), сгруппированных по z

1 голос
/ 12 марта 2019

Если у вас есть только небольшое количество групп (z), но большое количество категорий (x), вы можете преобразовать данные в широкий формат и начать с этого.Вот решение для простого примера.

> library(data.table)
> library(reshape2)
> 
> df_reshape = dcast(x~z, data=df, value.var="y")
> setDT(df_reshape)
> setnames(df_reshape,c(as.character(seq(1,4,1))),c(paste("x",as.character(seq(1,4,1)), sep="")))
> head(df_reshape)
   x x1 x2 x3 x4
1: A 43 22 12 12
2: B 32 32 13  4
3: C 45 52 23  5
> df_reshape[,.(diff1=x1-x2,diff2=x2-x3,diff3=x3-x4),by=x][,.(group1 = sum(diff1>0),group2 =sum(diff2>0),group3 = sum(diff3>0))]
   group1 group2 group3
1:      1      3      2
1 голос
/ 12 марта 2019

Вы можете использовать dplyr и mutate для каждой группы:

library(dplyr)
final.df <- df %>%
  group_by(x) %>%
  mutate(y = y - lead(y, 1)) %>%
  arrange(z, x) %>%
  filter(!is.na(y))
final.df

# A tibble: 9 x 3
# Groups:   x [3]
  x         z     y
  <fct> <dbl> <dbl>
1 A         1    21
2 B         1     0
3 C         1    -7
4 A         2    10
5 B         2    19
6 C         2    29
7 A         3     0
8 B         3     9
9 C         3    18

И использовать summarise для совокупности:

final.df %>%
  group_by(z) %>%
  summarise(lower = sum(y > 0))
# A tibble: 3 x 2
      z lower
  <dbl> <dbl>
1     1     1
2     2     3
3     3     2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...