Bagaimana cara mengambil perbedaan antara variabel dan lag yang ditentukan berdasarkan tanggal bulan per grup?

Pada dasarnya, saya memiliki kumpulan data dengan variabel yang menunjukkan grup, tanggal dan nilai variabel. Saya perlu mengambil selisih antara nilai dan nilai akhir tahun sebelumnya per kelompok. Karena datanya seimbang, saya mencoba melakukannya dengan dplyr::lag, memasukkan lag berdasarkan bulan pengamatan:

x <- x %>% group_by(g) %>% mutate(y = v - lag(v, n=month(d))

Namun hal ini tidak berhasil.

Hasilnya seharusnya:

Kumpulan data tiruan:

x <- data.frame('g'=c('B','B','B','C','A','A','A','A','A','A'),'d'=c('2018-11-30', '2018-12-31','2019-01-31','2019-12-31','2016-12-31','2017-11-30','2017-12-31','2018-12-31','2019-01-31','2019-02-28'),'v'=c(300,200,250,100,400,150,200,500,400,500))

Variabel yang diinginkan:

y <- c(NA,NA,-50,NA,NA,-250,-200,300,-100,0)

Kumpulan data baru:

cbind(x,y)

person Ramiro    schedule 04.12.2019    source sumber
comment
Dalam kumpulan data tiruan Anda hanya ada 1 grup: A dan ada 2 tahun: 2018 & 2019, maka 31-12-2018 akan menjadi satu-satunya akhir tahun sebelumnya per grup. Saya berasumsi tidak ada 3 tahun berturut-turut per grup (jika tidak, akan ada 2 tahun akhir sebelumnya per grup). Kemudian Anda dapat 1) mengekstrak year component of the date - 1 untuk mendapatkan tahun sebelumnya, dan 2) menggunakan max() untuk mendapatkan akhir tahun.   -  person FannieY    schedule 05.12.2019
comment
Maaf, saya akan membuat kumpulan data tiruan lebih komprehensif. Memang, itulah yang ingin saya lakukan. Namun demikian, dalam pipa dplyr bagaimana cara mengambil nilai grup yang sama dengan tahun = tahun-1 dan bulan maksimum? Dengan kata lain, buatlah variabel yaitu y = x - x[tahun==tahun-1 & bulan=maks(bulan pada tahun itu)]?   -  person Ramiro    schedule 05.12.2019
comment
Saya khawatir saya tidak bisa mendapatkan nilai variabel yang Anda inginkan (NA, NA, -50, NA, 500, 100, 0). Jika inputnya adalah data.frame('g'=c('B','B','B','C','A','A','A'),'d'=c(' 30-11-2018', '31-12-2018','31-01-2019','31-12-2017','31-12-2018','31-01-2019','2019- 02-28'),'v'=c(300,200,250,400,500,400,500)), keluaran yang saya harapkan y adalah: (NA, NA, 50, NA, NA, -100, 0).   -  person FannieY    schedule 05.12.2019
comment
Memang benar, kesalahan saya (pada tahap terakhir saya ingin akhir tahun tidak mengambil NA tetapi nilainya sendiri, meskipun hal itu dapat dengan mudah dilakukan dengan klausa ifelse).   -  person Ramiro    schedule 05.12.2019


Jawaban (2)


Ide melalui dplyr dapat berupa mencari hari terakhir, mendapatkan indeks dan menggunakannya untuk mengurangi dan kemudian mengonversi ke NA, yaitu.

library(dplyr)

x %>% 
 group_by(g) %>% 
 mutate(new = which(sub('^[0-9]+-([0-9]+-[0-9]+)$', '\\1', d) == '12-31'), 
        y = v - v[new], 
        y = replace(y, row_number() <= new, NA)) %>% 
 select(-new)

yang memberikan,

# A tibble: 7 x 4
# Groups:   g [3]
  g     d              v     y
  <fct> <fct>      <dbl> <dbl>
1 B     2018-11-30   300    NA
2 B     2018-12-31   200    NA
3 B     2019-01-31   250    50
4 C     2017-12-31   400    NA
5 A     2018-12-31   500    NA
6 A     2019-01-31   400  -100
7 A     2019-02-28   500     0
person Sotos    schedule 05.12.2019
comment
Itu tidak berhasil karena kumpulan data saya memiliki lebih dari dua tahun per kelompok. Bagaimana cara menyesuaikan penguraian sehingga mencari nilai yang memiliki tahun = tahun-1 dan '12-31' seperti pada pendekatan ini? Saya tidak terbiasa dengan ekspresi reguler - person Ramiro; 05.12.2019
comment
Ini adalah detail penting yang harus diabaikan. Harap perbarui kumpulan data Anda dan keluaran yang diharapkan dalam pertanyaan Anda - person Sotos; 05.12.2019
comment
Pendekatan Anda persis seperti yang saya inginkan, tetapi saya ingin new merujuk ke %y-1+'-12-31' - person Ramiro; 05.12.2019
comment
Menambahkannya di kumpulan data - person Ramiro; 05.12.2019

Pada akhirnya saya memutuskan untuk membuat variabel tambahan ('eoy') untuk menunjukkan baris akhir tahun yang sesuai per grup untuk setiap baris. Ini memerlukan perulangan dan tidak efisien tetapi memfasilitasi sisa perhitungan yang bergantung pada hal ini. Perhitungan yang diinginkan akan menjadi:

bermutasi('y'= x - x[eoy])

person Ramiro    schedule 05.12.2019