จัดกลุ่มตามและค้นหาหมายเลขที่ใกล้ที่สุด

ข้อมูลมีให้ที่ด้านล่างของหน้า ฉันมี 2 เฟรมข้อมูล df1 และ 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

กรอบข้อมูลทั้งสองมีข้อมูลหุ้นและแบ่งปันคอลัมน์ "สัญลักษณ์" ฉันต้องการจัดกลุ่ม df2 ด้วย 2 คอลัมน์ และค้นหาการประท้วงที่ใกล้เคียงที่สุดกับคอลัมน์ราคาใน df1

ผลลัพธ์จะมีลักษณะเช่นนี้

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

นี่คือ 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))

นี่ 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))

ฉันสนใจคำตอบของ @akrun data.table อย่างไรก็ตาม ฉันไม่ได้รับผลลัพธ์ที่ต้องการอย่างเต็มที่ 0719 สำหรับ SPY หายไป

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 แหล่งที่มา
comment
โปรดทราบว่าผลลัพธ์ที่คาดหวังจะเป็น 100 แทนที่จะเป็น 105   -  person akrun    schedule 05.06.2019


คำตอบ (3)


เราสามารถใช้การรวมแบบกลิ้งหลังจากสร้างชุดค่าผสมกับองค์ประกอบ unique ของ 'หมดอายุ' จากชุดข้อมูลที่สอง

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

หรือทำ full_join และ slice ตามความแตกต่าง minimum absolute ระหว่างคอลัมน์ 'ราคา' และ 'การนัดหยุดงาน' หลังจากจัดกลุ่มตาม 'ทิกเกอร์', 'หมดอายุ'

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
สวัสดีอัคร. ฉันสนใจ data.table จริงๆ แต่ฉันไม่ได้รับผลลัพธ์ทั้งหมด ดูเหมือนว่า 719 สำหรับ SPY จะหายไป ฉันได้แก้ไขผลลัพธ์ลงในโพสต์ต้นฉบับของฉันแล้ว - person Jordan Wrong; 05.06.2019
comment
สวัสดีอัครา ขอบคุณสำหรับทุกสี อย่างไรก็ตาม ฉันต้องการมันเป็นพิเศษเพื่อเลือกการประท้วงที่ใกล้กับเครื่องหมาย 100 มากที่สุด ซึ่งก็คือ 105 ไม่ใช่ 100 - person Jordan Wrong; 05.06.2019
comment
ขอโทษจริงๆ. ความผิดพลาดของฉัน. ขอบคุณมาก!!! นี่ทำให้ฉันหนักใจจริงๆ - person Jordan Wrong; 05.06.2019

tidyverse คำตอบ:

library(tidyverse)

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

เอาท์พุท:

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
ไม่มีปัญหา. ฉันขอแนะนำให้ทดสอบความเครียดในโซลูชันเหล่านี้โดยตั้งค่าข้อมูลที่มีค่าใกล้เคียงที่สุดสองค่า จะเกิดอะไรขึ้นกับการผูกเน็คไท? คุณอยากให้เกิดอะไรขึ้น? พยายามทำลายมันเพื่อให้แข็งแกร่งขึ้น - person Marian Minar; 05.06.2019
comment
ดีใจที่คุณเพิ่มสีสัน ฉันสามารถเพิ่มแนวคิดนี้ให้กับฟังก์ชันอื่นๆ ของฉันได้! - person Jordan Wrong; 05.06.2019

บ่อยครั้งฉันชอบใช้ distinct() เพื่อเลือกค่าที่เล็กที่สุดหรือใหญ่ที่สุดต่อกลุ่ม (หรือผลลัพธ์อื่นใดที่เป็น arrange() จริงๆ) อันดับแรก ฉันจะจัดเรียงข้อมูลตามผลต่างสัมบูรณ์ของ strike และ Price มันเร็วมากเมื่อเทียบกับ group_by() ตามค่าเริ่มต้น distinct() จะเลือกแถวแรกต่อชุดค่าผสมที่กำหนด และหากเราใช้ .keep_all = TRUE คอลัมน์อื่นๆ จะถูกเก็บไว้

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
ขอโทษ. แก้ไขไม่ดี ขอบคุณสำหรับความช่วยเหลือของคุณ pasi มันใช้งานได้ดี - person Jordan Wrong; 05.06.2019