Сравнение значения определенной строки со всеми предыдущими строками в data.table - PullRequest
3 голосов
/ 29 февраля 2020

У меня есть набор данных, содержащий фирмы, занимающиеся определенной категорией продуктов. Набор данных выглядит следующим образом:

df <- data.table(year=c(1979,1979,1980,1980,1980,1981,1981,1982,1982,1982,1982),
                 category = c("A","A","B","C","A","D","C","F","F","A","B"))

Я хочу создать новую переменную следующим образом: Если фирма входит в новую категорию, в которую она ранее не занималась в предыдущие годы (не в том же году) ) , то эта запись помечается как «НОВАЯ», в противном случае она будет помечена как «СТАРЫЙ».

Таким образом, желаемый результат будет:

    year   category   Newness
 1: 1979        A     NEW
 2: 1979        A     NEW
 3: 1980        B     NEW
 4: 1980        C     NEW
 5: 1980        A     OLD
 6: 1981        D     NEW
 7: 1981        C     OLD
 8: 1982        F     NEW
 9: 1982        F     NEW
10: 1982        A     OLD
11: 1982        B     OLD

I Я склонен использовать data.table, поскольку у меня более 1,5 миллионов наблюдений, и я хочу иметь возможность реплицировать решение путем группировки по идентификаторам фирм.

Любая помощь будет принята с благодарностью, и заранее благодарю.

Ответы [ 4 ]

2 голосов
/ 29 февраля 2020

Вы можете решить вашу проблему следующим образом:

# Method 1:
setDT(df, key = "year")[, Newness := fifelse(year == year[1L], "NEW", "OLD"), category]  

# Method 2
setDT(df, key = "year")[, Newness := c("NEW", "OLD")[match(year, year[1L], 2)], category]

#      year category Newness
# 1:   1979        A     NEW
# 2:   1979        A     NEW
# 3:   1980        B     NEW
# 4:   1980        C     NEW
# 5:   1980        A     OLD
# 6:   1981        D     NEW
# 7:   1981        C     OLD
# 8:   1982        F     NEW
# 9:   1982        F     NEW
# 10:  1982        A     OLD
# 11:  1982        B     OLD
2 голосов
/ 29 февраля 2020

Вы можете использовать duplicated + ifelse в базе R:

transform(df,Newness = ifelse(duplicated(category)==duplicated(df),"New","Old"))
    year category Newness
 1: 1979        A     New
 2: 1979        A     New
 3: 1980        B     New
 4: 1980        C     New
 5: 1980        A     Old
 6: 1981        D     New
 7: 1981        C     Old
 8: 1982        F     New
 9: 1982        F     New
10: 1982        A     Old
11: 1982        B     Old

в data.table, которую вы сделаете:

library(data.table)
df[,Newness := ifelse(duplicated(.SD)==duplicated(category),"New","Old")]
df
    year category Newness
 1: 1979        A     New
 2: 1979        A     New
 3: 1980        B     New
 4: 1980        C     New
 5: 1980        A     Old
 6: 1981        D     New
 7: 1981        C     Old
 8: 1982        F     New
 9: 1982        F     New
10: 1982        A     Old
11: 1982        B     Old
2 голосов
/ 29 февраля 2020

Мы можем присвоить первый год как "NEW" для каждого category.

library(data.table)
df[, Newness := c("NEW", "OLD")[(match(year, unique(year)) > 1) + 1], category]
df

#    year category Newness
# 1: 1979        A     NEW
# 2: 1979        A     NEW
# 3: 1980        B     NEW
# 4: 1980        C     NEW
# 5: 1980        A     OLD
# 6: 1981        D     NEW
# 7: 1981        C     OLD
# 8: 1982        F     NEW
# 9: 1982        F     NEW
#10: 1982        A     OLD
#11: 1982        B     OLD

Аналогично, в dplyr это можно записать как:

library(dplyr)
df %>%
  group_by(category) %>%
  mutate(Newness =  c("NEW", "OLD")[(match(year, unique(year)) > 1) + 1])
1 голос
/ 29 февраля 2020

Другой вариант data.table:

df[, Newness := "OLD"][
    unique(df, by="category"), on=.(year, category), Newness := "NEW"]

временной код:

library(data.table)
set.seed(0L)
nr <- 1.5e6
df <- data.table(year=sample(1970:2019, nr, TRUE), category=sample(1e4, nr, TRUE))
setkey(df, year, category)

mtd0 <- function()
    df[, Newness := c("NEW", "OLD")[(match(year, unique(year)) > 1) + 1], category]

mtd1 <- function() 
    df[, Newness := ifelse(duplicated(.SD)==duplicated(category),"New","Old")]

mtd2 <- function()
    df[, Newness := "OLD"][
        unique(df, by="category"), on=.(year, category), Newness := "NEW"]

microbenchmark::microbenchmark(times=3L,
    mtd0(), mtd1(), mtd2())

время:

Unit: milliseconds
   expr      min       lq      mean   median       uq      max neval
 mtd0() 154.6129 167.5908 182.70500 180.5687 196.7511 212.9334     3
 mtd1() 343.3772 375.0303 395.08653 406.6835 420.9412 435.1989     3
 mtd2()  41.4178  42.0520  45.40527  42.6862  47.3990  52.1118     3
...