【问题标题】:Using dplyr in a function in R, and then a for loop to carry out the function在 R 中的函数中使用 dplyr,然后使用 for 循环来执行该函数
【发布时间】:2018-11-30 23:39:39
【问题描述】:

我有一个数据框,我们称之为 df1,看起来像这样:

product_key              month    price     productage

00020e32-8ecd53a64715   201508  65.00000    1
00020e32-8ecd53a64715   201509  65.00000    2
00020e32-8ecd53a64715   201510  65.00000    3
000340b8-60fb50bacac8   201504  55.00000    1
000340b8-60fb50bacac8   201505  55.00000    2
000340b8-60fb50bacac8   201506  53.16667    3
000340b8-60fb50bacac8   201507  27.50000    4
000340b8-60fb50bacac8   201508  27.50000    5
000340b8-60fb50bacac8   201509  27.50000    6
000340b8-60fb50bacac8   201510  27.50000    7
000458f1-9304a2fdb6ae   201506  49.00000    1
000458f1-9304a2fdb6ae   201507  49.00000    2
000458f1-9304a2fdb6ae   201508  49.00000    3
000458f1-9304a2fdb6ae   201509  49.00000    4
000458f1-9304a2fdb6ae   201510  49.00000    5

我想要做的是过滤掉数据集中已存在 1 个月的所有产品(例如 filter(productage ==1)),然后从这些项目及其价格中创建一个单位价值指数。然后我想对已经在数据集中存在 2 个月然后 3 个月的产品做同样的事情......

到目前为止我所做的,但啰嗦的是:

第 1 个月

df1month1 <- df1 %>%
filter(productage == 1)

每种产品的月平均价格

df1_UVIMONTH1<-df1month1%>%
  group_by(month)%>%
  summarise(aveprice=mean(price))

第 1 个月的紫外线指数, 计算 UVI 价格指数

  df1UVIMONTH1<-df1_UVIMONTH1%>%
  mutate(month=as.numeric(month))%>%
  arrange(month)%>%
  mutate(UVI=(aveprice/lag(aveprice)))%>%
  mutate(UVI=case_when(month==min(month)~1,
                       month!=min(month)~ UVI))%>%
  mutate(chained=cumprod(UVI))

但是,为数据集中的每个产品年龄(最多可以有 26 个)和 10 个不同的数据集执行此操作既冗长又乏味。我正在努力提高这个过程的效率,但我正在苦苦挣扎。

我试图创建一个函数:

product_by_age <- function(df1, age){
  filter_by_month <- df1 %>%
    filter(productage %in% age) %>%
    group_by(month) %>%
    summarise(aveprice=mean(price))

  UVI_index <- filter_by_month %>%
    mutate(month=as.numeric(month))%>%
    arrange(month)%>%
    mutate(UVI=(aveprice/lag(aveprice)))%>%
    mutate(UVI=case_when(month==min(month)~1,
                         month!=min(month)~ UVI))%>%
    mutate(chained=cumprod(UVI))
}



df1productage <- data.frame(age = unique(df1$productage), stringsAsFactors = FALSE)

result <- data.frame()
for (i in df1productage:length(df1productage)) {
  sba <- product_by_age(df1, df1productage[i])
  result <- rbind(result, sba)
}

但这对我不起作用。请帮忙!如果有人能想到更好的方法来解决这个问题,请告诉我。如果你完全重做这个功能,我也不介意。

要重新创建我的示例数据集,您可以使用:

product_key <- c(“00020e32-8ecd53a64715”, “00020e32-8ecd53a64715”, ”00020e32-8ecd53a64715”, “000340b8-60fb50bacac8”, “000340b8-60fb50bacac8”, “000340b8-60fb50bacac8”, “000340b8-60fb50bacac8”, “000340b8-60fb50bacac8”, “000340b8-60fb50bacac8”,   “000340b8-60fb50bacac8”, “000458f1-9304a2fdb6ae”, “000458f1-9304a2fdb6ae”, “000458f1-9304a2fdb6ae”, “000458f1-9304a2fdb6ae”, ”000458f1-9304a2fdb6ae”)
month <- c("201508", "201509", "201510", "201504", "201505", "201506", "201507", "201508", "201509", "201510", "201506", "201507", "201508", "201509", "201510")
price <- c("65", "65", "65", "55", "55", "53.16667", "27.5", "27.5", "27.5", "27.5", "49", "49", "49", "49", "49")
productage <- c("1", "2", "3", "1", "2", "3", "4", "5", "6", "7", "1", "2", "3", "4", "5")
df1 <- data.frame(product_key, month, price, productage)

【问题讨论】:

  • ...group_by(productage, month) ...?
  • 我认为错误在df1productage:length(df1productage
  • @Tjebo 它不起作用,因为您将所有产品年龄都包含在一个数据集中,因此您还必须在该阶段添加某种过滤器功能才能获得结果你自找的。这再次意味着将过滤器功能更改为按每个产品年龄进行过滤 - 这是漫长而乏味的。
  • 另外,在函数price_currentdaymode 内部有没有在输入数据集中。您的数字列示例应该不带引号。它基于此创建factorcharacter
  • @akrun - 我已经更新了,这就是我的数据集中调用的价格变量,但在本例中为了方便起见将其更改为价格。我创建了一个名为 df1product age 的数据框,其中包含所有唯一的产品年龄值,因此认为这会起作用。我不明白为什么不是?

标签: r function for-loop dplyr


【解决方案1】:

我们需要稍微改变一下循环。假设我们正在遍历'df1productage'中的行序列,并且'result'被初始化为一个空白的data.frame,

for(i in seq_len(nrow(df1productage))) {
    result <- rbind(result, product_by_age(df1, df1productage$age[i]))
 }

dim(result)
#[1] 15  4

或者使用tidyverse方式

library(tidyverse)
map_df(df1productage %>% 
              pull(age), ~    
                    product_by_age(df1, .x), .id = 'grp')
# A tibble: 15 x 5
#   grp   month aveprice   UVI chained
#   <chr> <dbl>    <dbl> <dbl>   <dbl>
# 1 1         1     55   1       1    
# 2 1         3     49   0.891   0.891
# 3 1         5     65   1.33    1.18 
# 4 2         2     55   1       1    
# 5 2         4     49   0.891   0.891
# 6 2         6     65   1.33    1.18 
# 7 3         3     53.2 1       1    
# 8 3         5     49   0.922   0.922
# 9 3         7     65   1.33    1.22 
#10 4         4     27.5 1       1    
#11 4         6     49   1.78    1.78 
#12 5         5     27.5 1       1    
#13 5         7     49   1.78    1.78 
#14 6         6     27.5 1       1    
#15 7         7     27.5 1       1    

编辑:在map_df 中添加了一个标识符列

【讨论】:

  • 谢谢!这非常有效(我刚刚使用了 dplyr 方式) - 有没有一种方法可以为我的结果获取每个产品年龄的单独数据框?或者至少将产品年龄添加到单位价值索引旁边的另一列中,并在函数中的某个位置对其进行编码,因为目前我有索引变量,但它没有告诉我它们对应的项目年龄。再次感谢
  • @JayJ,您可以在map_df 中使用.id,即map_df(df1productage %&gt;% ...), .id = 'grp')
【解决方案2】:

它适用于分组,没有新功能!

require(dplyr)

df1%>%
  group_by(month, productage)%>%
  summarise(aveprice=mean(price)) %>% arrange(productage, month) %>%
    group_by(productage)%>%
    mutate(UVI=c(1, aveprice[2:length(aveprice)]/aveprice[1:length(aveprice)-1])) %>%
  mutate(chained=cumprod(UVI))

 ### Group and then regroup. and I have modified your mutate code which was using 'lag' 

# A tibble: 15 x 5
# Groups:   productage [7]
    month productage aveprice   UVI chained
    <dbl> <chr>         <dbl> <dbl>   <dbl>
 1 201504 1              55.0 1.00    1.00 
 2 201506 1              49.0 0.891   0.891
 3 201508 1              65.0 1.33    1.18 
 4 201505 2              55.0 1.00    1.00 
 5 201507 2              49.0 0.891   0.891
 6 201509 2              65.0 1.33    1.18 
 7 201506 3              53.2 1.00    1.00 
 8 201508 3              49.0 0.922   0.922
 9 201510 3              65.0 1.33    1.22 
10 201507 4              27.5 1.00    1.00 
11 201509 4              49.0 1.78    1.78 
12 201508 5              27.5 1.00    1.00 
13 201510 5              49.0 1.78    1.78 
14 201509 6              27.5 1.00    1.00 
15 201510 7              27.5 1.00    1.00 

现在您可以简单地使用split 来按列产品拆分

【讨论】:

  • 谢谢 - 这并不能直接回答问题(针对读者),但它完全符合我的要求,让我的代码更简单、更高效!
猜你喜欢
  • 2019-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-03
  • 1970-01-01
  • 2022-10-21
相关资源
最近更新 更多