Kelompokkan Berdasarkan dan Temukan Nomor Terdekat

Data disediakan di bagian bawah halaman. Saya memiliki 2 bingkai data df1 dan df2.

df1:
ticker   Price
<chr>    <dbl>
SPY      200.00
AAPL     100.00

df2:
ticker  expiration   strike
<chr>    <dbl>       <dbl>
SPY      0621         180
SPY      0621         205
SPY      0719         180
SPY      0719         205
AAPL     0621          75
AAPL     0621         105
AAPL     0719          75
AAPL     0719         105

Kedua bingkai data memiliki data stok dan berbagi kolom "ticker". Saya ingin mengelompokkan df2 berdasarkan 2 kolom dan kemudian menemukan pukulan terdekat dengan kolom Harga di df1.

Outputnya akan terlihat seperti ini.

df3 = df2 %>% group_by(ticker, expiration)%>% #which[abs(df1$Price - df2$strike) is closest to 0]

output:
ticker   expiration  strike
<chr>     <dbl>       <dbl>
SPY       0621         205
SPY       0719         205
AAPL      0621         105
AAPL      0719         105

Ini df1

structure(list(ticker = structure(2:1, .Label = c("AAPL", "SPY"
), class = "factor"), Price = c(200, 100)), class = "data.frame", row.names = c(NA, 
-2L))

Ini df2

structure(list(ticker = structure(c(2L, 2L, 2L, 2L, 1L, 1L, 1L, 
1L), .Label = c("AAPL", "SPY"), class = "factor"), expiration = c(621, 
621, 719, 719, 621, 621, 719, 719), strike = c(180, 205, 180, 
205, 75, 100, 75, 100)), class = "data.frame", row.names = c(NA, 
-8L))

Saya tertarik dengan jawaban @akrun data.table. Namun saya tidak mendapatkan hasil penuh yang diinginkan. 0719 untuk SPY tidak ada.

library(data.table)
setDT(df2)[, Price := strike][df1, on = .(ticker, Price), roll = -Inf]
ticker expiration strike Price
1:    SPY        621    205   200
2:   AAPL        621    100   100
3:   AAPL        719    100   100

person Jordan Wrong    schedule 05.06.2019    source sumber
comment
Perhatikan bahwa keluaran yang diharapkan adalah 100, bukan 105   -  person akrun    schedule 05.06.2019


Jawaban (3)


Kita dapat menggunakan rolling join setelah membuat kombinasi dengan unique elemen 'kedaluwarsa' dari dataset kedua

library(data.table)
library(tidyr)
df1N <- crossing(df1, expiration = unique(df2$expiration))
setDT(df2)[, Price := strike][df1N, on = .(ticker, expiration, Price), roll = -Inf]
#    ticker expiration strike Price
#1:    SPY        621    205   200
#2:    SPY        719    205   200
#3:   AAPL        621    100   100
#4:   AAPL        719    100   100

Atau lakukan full_join lalu slice berdasarkan minimum absolute selisih antara kolom 'Harga' dan 'strike' setelah dikelompokkan berdasarkan 'ticker', 'expiration'

library(dplyr)
full_join(df1, df2) %>% 
    group_by(ticker, expiration) %>% 
    slice(which.min(abs(Price - strike)))
# A tibble: 4 x 4
# Groups:   ticker, expiration [4]
#  ticker Price expiration strike
#  <fct>  <dbl>      <dbl>  <dbl>
#1 AAPL     100        621    100
#2 AAPL     100        719    100
#3 SPY      200        621    205
#4 SPY      200        719    205
person akrun    schedule 05.06.2019
comment
Hai Akrun. Saya sangat tertarik dengan cara data.table namun saya tidak mendapatkan hasil penuh. Sepertinya 719 untuk SPY hilang. Saya telah mengedit hasilnya ke dalam posting asli saya. - person Jordan Wrong; 05.06.2019
comment
Hai akrun terima kasih untuk semua warnanya. Namun saya secara khusus membutuhkannya untuk memilih pukulan yang paling dekat dengan tanda 100 yaitu 105 bukan 100. - person Jordan Wrong; 05.06.2019
comment
sangat menyesal. Kesalahanku. Terima kasih banyak!!! Ini sungguh menyusahkan saya. - person Jordan Wrong; 05.06.2019

Jawaban tidyverse:

library(tidyverse)

df2 %>% 
  left_join(df1) %>%
  mutate(diff = abs(strike - Price)) %>%
  group_by(ticker, expiration) %>%
  top_n(-1, wt = diff) %>%
  select(-Price, -diff)

Keluaran:

Joining, by = "ticker"
# A tibble: 4 x 3
# Groups:   ticker, expiration [4]
  ticker expiration strike
  <fct>       <dbl>  <dbl>
1 SPY           621    205
2 SPY           719    205
3 AAPL          621    100
4 AAPL          719    100
person Marian Minar    schedule 05.06.2019
comment
Tidak masalah. Saya merekomendasikan stress-testing terhadap solusi ini dengan menyiapkan data yang memiliki DUA nilai terdekat. Apa yang terjadi dengan dasi? Apa yang Anda ingin terjadi? Cobalah untuk mematahkannya agar lebih kuat. - person Marian Minar; 05.06.2019
comment
Senang sekali Anda menambahkan beberapa warna. Saya dapat menambahkan konsep ini ke banyak fungsi saya yang lain! - person Jordan Wrong; 05.06.2019

Seringkali saya suka menggunakan distinct() untuk memilih nilai terkecil atau terbesar per grup (atau hasil arrange() lainnya). Disini saya pertama-tama menyusun datanya berdasarkan selisih mutlak strike dan Price. Ini sangat cepat dibandingkan dengan group_by(). Secara default distinct() memilih baris pertama per kombinasi yang diberikan dan jika kita menggunakan .keep_all = TRUE kolom lainnya dipertahankan.

library(dplyr)

df2 %>% 
  left_join(df1) %>% 
  arrange(ticker, expiraton, abs(strike - Price)) %>% 
  distinct(ticker, expiraton, .keep_all = TRUE)
#> Joining, by = "ticker"
#>   ticker expiraton strike Price
#> 1   AAPL       621    100   100
#> 2   AAPL       719    100   100
#> 3    SPY       621    205   200
#> 4    SPY       719    205   200
person pasipasi    schedule 05.06.2019
comment
Maaf. editan buruk. Terima kasih atas bantuannya pasi. Itu berhasil dengan baik. - person Jordan Wrong; 05.06.2019