R:分组依据并将通用函数应用于两列
R: Group by and Apply a general function to two columns
您好,我想对两个数据框列进行分组,并将一个函数应用于另外两个数据框列。
例如,
ticker <- c("A", "A", 'A', "B", "B", "B")
date <- c(1,1,2,1,2,1)
ret <- c(1,2,4,6,9,5)
vol <- c(3,5,1,6,2,3)
dat <- data.frame(ticker,date,ret,vol)
对于每个代码和每个日期,我想计算其 PIN。
现在,为了避免进一步的混淆,也许只说出实际功能会有所帮助。 YZ 是 InfoTrad 包中的一个函数,YZ 只接受具有两列的数据框。它使用一些优化工具和 returns 估计的 PIN。
install.packages(InfoTrad)
library(InfoTrad)
get_pin_yz <- function(data) {
return(YZ(data[ ,c('volume_krw_buy', 'volume_krw_sell')])[['PIN']])
}
我知道如何在 R 中使用 for 循环执行此操作。但是 for 循环的计算成本非常高,可能需要数周才能完成 运行 我的大型数据集。因此,我想问一下如何使用groupby来做到这一点。
# output format is wide wrt long format as "dat"
dat_w <- data.frame(ticker = NA, date = NA, PIN = NA)
for (j in c("A", "B")){
for (k in c(1:2)){
subset <- dat %>% subset((ticker == j & date == k), select = c('ret', "vol"))
new_row <- data.frame(ticker = j, date = k, PIN = YZ(subset)$PIN)
dat_w <- rbind(dat_w, new_row)
}
}
dat_w <- dat_w[-1, ]
dat_w
不知道这是否可以帮助你帮助我 -- 我知道如何在 python 中做到这一点:我只是写了一个函数和 运行 df.groupby(['ticker','date']).apply(function)
.
最后,想要的数据框是:
ticker <- c('A','A','B','B')
date <- c(1,2,1,2)
PIN <- c(1.05e-17,2.81e-09,1.12e-08,5.39e-09)
data.frame(ticker,date,PIN)
有人能帮忙吗?
谢谢!
最佳,
达西
以前的东西(随意忽略)
以前,我这样写:
我的函数是:
get_rv <- function(data) {
return(data[['vol']] + data[['ret']])
}
我想要的是:
ticker_wanted <- c('A','A', 'B', 'B')
date_wanted <- c(1,2,1,2)
rv_wanted <- c(7,5,10,11)
df_wanted <-data.frame(ticker_wanted,date_wanted,rv_wanted)
但这并不是我的实际功能。 vol+ret 只是一个例子。我对更一般的情况更感兴趣:如何分组并将通用函数应用于两个或多个数据帧。我使用 vol + ret 只是因为我不想让别人在他们的 PC 上安装一些可能不相关的软件包来打扰他们。
根据 real-life 示例更新:
您可以采用如下直接方法:
library(tidyverse)
library(InfoTrad)
dat %>%
group_by(ticker, date) %>%
summarize(PIN = YZ(as.data.frame(cur_data()))$PIN)
# A tibble: 4 x 3
# Groups: ticker [2]
ticker date PIN
<chr> <dbl> <dbl>
1 A 1 1.05e-17
2 A 2 1.56e- 1
3 B 1 1.12e- 8
4 B 2 7.07e- 9
这里的困难在于 YZ 函数只接受真实的数据帧,不接受 tibbles 并且它 returns 几个值,而不仅仅是 PIN。
从理论上讲,您可以将其包装到您自己的函数中,然后 运行 您自己的函数,就像我在下面的示例中展示的那样,但也许这种方式已经可以解决问题了。
我也不希望它 运行 比 for 循环快得多。看来这个YZ函数有一些more-than-linear 运行的时间,所以传递更大的数据量还是需要一些时间。您可以尝试从一小组数据开始,然后通过将数据大小增加 10 倍来重复它,然后检查它有多快 运行s。
在你的例子中,你可以这样做:
my_function <- function(data) {
data %>%
summarize(rv = sum(ret, vol))
}
library(tidyverse)
df %>%
group_by(ticker, date) %>%
my_function()
# A tibble: 4 x 3
# Groups: ticker [2]
ticker date rv
<chr> <dbl> <dbl>
1 A 1 7
2 A 2 5
3 B 1 10
4 B 2 11
但是正如我在评论中提到的,我不确定这个一般示例是否对您的 real-life 用例有帮助。
也可能是您不需要创建自己的函数,因为 built-in 函数已经存在。就像在示例中一样,您最好直接总结而不是将其包装到函数中。
你能做到吗? (以 summarize 作为您的功能的示例):
ticker <- c("A", "A", 'A', "B", "B", "B")
date <- c(1,1,2,1,2,1)
ret <- c(1,-2,4,6,9,-5)
vol <- c(3,5,1,6,2,3)
df <- data.frame(ticker,date,ret,vol)
df_wanted <- get_rv(df)
get_rv <- function(data){
result <- data %>%
group_by(ticker,date) %>%
summarise(rv =sum(ret) + sum(vol)) %>%
as.data.frame()
names(result) <- c('ticker_wanted', 'date_wanted', 'rv_wanted')
return(result)
}
假设你的dataframe如下:
data <- data.frame(ticker,date,ret,vol)
使用 split
根据股票代码和日期的值将您的数据帧拆分为一组数据帧。
dflist = split(data, f = list(data$ticker, data$date), drop = TRUE)
现在使用 lapply
或 sapply
到 运行 dflist 的每个数据帧成员上的函数 YZ()。
pins <- lapply(dflist, function(x) YZ(x)$PIN)
您好,我想对两个数据框列进行分组,并将一个函数应用于另外两个数据框列。 例如,
ticker <- c("A", "A", 'A', "B", "B", "B")
date <- c(1,1,2,1,2,1)
ret <- c(1,2,4,6,9,5)
vol <- c(3,5,1,6,2,3)
dat <- data.frame(ticker,date,ret,vol)
对于每个代码和每个日期,我想计算其 PIN。
现在,为了避免进一步的混淆,也许只说出实际功能会有所帮助。 YZ 是 InfoTrad 包中的一个函数,YZ 只接受具有两列的数据框。它使用一些优化工具和 returns 估计的 PIN。
install.packages(InfoTrad)
library(InfoTrad)
get_pin_yz <- function(data) {
return(YZ(data[ ,c('volume_krw_buy', 'volume_krw_sell')])[['PIN']])
}
我知道如何在 R 中使用 for 循环执行此操作。但是 for 循环的计算成本非常高,可能需要数周才能完成 运行 我的大型数据集。因此,我想问一下如何使用groupby来做到这一点。
# output format is wide wrt long format as "dat"
dat_w <- data.frame(ticker = NA, date = NA, PIN = NA)
for (j in c("A", "B")){
for (k in c(1:2)){
subset <- dat %>% subset((ticker == j & date == k), select = c('ret', "vol"))
new_row <- data.frame(ticker = j, date = k, PIN = YZ(subset)$PIN)
dat_w <- rbind(dat_w, new_row)
}
}
dat_w <- dat_w[-1, ]
dat_w
不知道这是否可以帮助你帮助我 -- 我知道如何在 python 中做到这一点:我只是写了一个函数和 运行 df.groupby(['ticker','date']).apply(function)
.
最后,想要的数据框是:
ticker <- c('A','A','B','B')
date <- c(1,2,1,2)
PIN <- c(1.05e-17,2.81e-09,1.12e-08,5.39e-09)
data.frame(ticker,date,PIN)
有人能帮忙吗?
谢谢!
最佳,
达西
以前的东西(随意忽略) 以前,我这样写: 我的函数是:
get_rv <- function(data) {
return(data[['vol']] + data[['ret']])
}
我想要的是:
ticker_wanted <- c('A','A', 'B', 'B')
date_wanted <- c(1,2,1,2)
rv_wanted <- c(7,5,10,11)
df_wanted <-data.frame(ticker_wanted,date_wanted,rv_wanted)
但这并不是我的实际功能。 vol+ret 只是一个例子。我对更一般的情况更感兴趣:如何分组并将通用函数应用于两个或多个数据帧。我使用 vol + ret 只是因为我不想让别人在他们的 PC 上安装一些可能不相关的软件包来打扰他们。
根据 real-life 示例更新:
您可以采用如下直接方法:
library(tidyverse)
library(InfoTrad)
dat %>%
group_by(ticker, date) %>%
summarize(PIN = YZ(as.data.frame(cur_data()))$PIN)
# A tibble: 4 x 3
# Groups: ticker [2]
ticker date PIN
<chr> <dbl> <dbl>
1 A 1 1.05e-17
2 A 2 1.56e- 1
3 B 1 1.12e- 8
4 B 2 7.07e- 9
这里的困难在于 YZ 函数只接受真实的数据帧,不接受 tibbles 并且它 returns 几个值,而不仅仅是 PIN。
从理论上讲,您可以将其包装到您自己的函数中,然后 运行 您自己的函数,就像我在下面的示例中展示的那样,但也许这种方式已经可以解决问题了。
我也不希望它 运行 比 for 循环快得多。看来这个YZ函数有一些more-than-linear 运行的时间,所以传递更大的数据量还是需要一些时间。您可以尝试从一小组数据开始,然后通过将数据大小增加 10 倍来重复它,然后检查它有多快 运行s。
在你的例子中,你可以这样做:
my_function <- function(data) {
data %>%
summarize(rv = sum(ret, vol))
}
library(tidyverse)
df %>%
group_by(ticker, date) %>%
my_function()
# A tibble: 4 x 3
# Groups: ticker [2]
ticker date rv
<chr> <dbl> <dbl>
1 A 1 7
2 A 2 5
3 B 1 10
4 B 2 11
但是正如我在评论中提到的,我不确定这个一般示例是否对您的 real-life 用例有帮助。
也可能是您不需要创建自己的函数,因为 built-in 函数已经存在。就像在示例中一样,您最好直接总结而不是将其包装到函数中。
你能做到吗? (以 summarize 作为您的功能的示例):
ticker <- c("A", "A", 'A', "B", "B", "B")
date <- c(1,1,2,1,2,1)
ret <- c(1,-2,4,6,9,-5)
vol <- c(3,5,1,6,2,3)
df <- data.frame(ticker,date,ret,vol)
df_wanted <- get_rv(df)
get_rv <- function(data){
result <- data %>%
group_by(ticker,date) %>%
summarise(rv =sum(ret) + sum(vol)) %>%
as.data.frame()
names(result) <- c('ticker_wanted', 'date_wanted', 'rv_wanted')
return(result)
}
假设你的dataframe如下:
data <- data.frame(ticker,date,ret,vol)
使用 split
根据股票代码和日期的值将您的数据帧拆分为一组数据帧。
dflist = split(data, f = list(data$ticker, data$date), drop = TRUE)
现在使用 lapply
或 sapply
到 运行 dflist 的每个数据帧成员上的函数 YZ()。
pins <- lapply(dflist, function(x) YZ(x)$PIN)