根据其他列

时间:2016-10-10 20:52:26

标签: r dataframe

我有一个数据框,其中包含一个日期列,一列int(在下面的示例中标记为value)和另外12个数字列,每列对应一个月并标记为X1(jan) )通过X12(dec)。

它看起来像:

date_var    value    X1       X2      X3     ...   X12
2016-01-01   100    1212     4161    9080    ...   383
2016-02-01   150    1212     4161    9080    ...   383
2016-03-01   150    1212     4161    9080    ...   383

我想要做的是创建一个新列,让我们称之为Z,它对应于value列中的数字,除以相应的每月值。

例如,在上表中,2016-01-01条目的Z将等于100/1212,而2016-02-01条目将替换为2的X2,而2016-03-01将具有{{ 1}}除以X3:

value

我尝试了各种方法,试图将date_var value X1 X2 X3 ... X12 Z 2016-01-01 100 1212 4161 9080 ... 383 0.0825 2016-02-01 150 1212 4161 9080 ... 383 0.0360 2016-03-01 150 1212 4161 9080 ... 383 0.0165 除以value,虽然这返回列表而不是按元素工作,因此显然不是正确的方法。

4 个答案:

答案 0 :(得分:2)

使用dplyrtidyr软件包的另一个好方法基本上采用R方法将信息转换为长数据帧格式(即同一列中的相同类型的信息,这里所有的X1 -X12)然后使用过滤条件仅考虑与日期变量中的月份匹配的月份值:

library(dplyr)
library(tidyr)
library(lubridate)

# test data frame (code from parksw3)
data <- data_frame(
  date_var = as.Date(c("2016-01-01", "2016-02-01", "2016-03-01")),
  value = c(100, 150, 150),
  X1 = rep(1212, 3),
  X2 = rep(4161, 3),
  X3 = rep(9080, 3),
  X12 = rep(383, 3)
) 

# calculate the resulting Z column
result <- data %>% 
  # gather all the month (X1-X12) values into long format 
  # with month_var and month_value as key/value pair
  gather(month_var, month_value, starts_with("X")) %>% 
  # only consider the month_value for the month_var that matches the date's month
  filter(month_var == paste0("X", month(date_var))) %>% 
  # calculate the derived quantity
  mutate(Z = value/month_value)

print(result)

##     date_var value month_var month_value          Z
##       <date> <dbl>     <chr>       <dbl>      <dbl>
## 1 2016-01-01   100        X1        1212 0.08250825
## 2 2016-02-01   150        X2        4161 0.03604903
## 3 2016-03-01   150        X3        9080 0.01651982

如果需要,可以将其合并回原始数据框:

data_all <- left_join(data, select(result, date_var, Z), by = "date_var")

print(data_all)

##     date_var value    X1    X2    X3   X12          Z
##       <date> <dbl> <dbl> <dbl> <dbl> <dbl>      <dbl>
## 1 2016-01-01   100  1212  4161  9080   383 0.08250825
## 2 2016-02-01   150  1212  4161  9080   383 0.03604903
## 3 2016-03-01   150  1212  4161  9080   383 0.01651982

答案 1 :(得分:1)

看看这个post。我认为应该有一个更简单的方法,但这是基于该帖子所做的事情,它们似乎都有效:

数据:

df <- data.frame(
    date_var = as.Date(c("2016-01-01", "2016-02-01", "2016-03-01")),
    value = c(100, 150, 150),
    X1 = rep(1212, 3),
    X2 = rep(4161, 3),
    X3 = rep(9080, 3),
    X12 = rep(383, 3)
)

方法1:

m <- paste0("X", month(df$date_var))
sub <- cbind(1:nrow(df),
    match(m, names(df))
)
Z2 <- df$value/as.numeric(df[sub])
df2 <- cbind(df, Z2)

方法2:

Z3 <- sapply(rownames(df), function(x){
    with(df[x,],{
        m <- month(date_var)
        value/get(paste0("X", m))
    })
})
df3 <- cbind(df, Z3)

结果:

##     date_var value   X1   X2   X3 X12         Z3
## 1 2016-01-01   100 1212 4161 9080 383 0.08250825
## 2 2016-02-01   150 1212 4161 9080 383 0.03604903
## 3 2016-03-01   150 1212 4161 9080 383 0.01651982
## 4 2017-02-01   150 1212 4161 9080 383 0.03604903

答案 2 :(得分:1)

作为对R索引的试验的探索 - 伪 - tidyverse答案。

首先让我们生成一些虚拟数据。

library(tidyverse)

data <- data_frame(
    date_var = seq(as.Date("2016-01-01"), by = "month", length.out = 12),
    value = ceiling(runif(12, 100, 200))
)

data %>%
    mutate(months = map(value, function(x){matrix(ceiling(runif(12, 50, 5000)), ncol = 12)}),
           months = map(months, as_data_frame)) %>%
    unnest(months) %>%
    as.data.frame() ->
    sample.data

head(sample.data)
#>     date_var value   V1   V2   V3   V4   V5   V6   V7   V8   V9  V10  V11  V12
#> 1 2016-01-01   147 2004 2456 3983 4464 2473 2824 2038 1354 3433   51  574 1381
#> 2 2016-02-01   170 2862 3579  543 1458 2472  826 3865  528  187  951 4732 1849
#> 3 2016-03-01   107 2860 1359 4366 1824  173 3541  624   76 4113  771  808 3457
#> 4 2016-04-01   115 1707 4015 3951 2774 2726 1789 2189 1903 1706  124 3679 1876
#> 5 2016-05-01   120 1058 4169 2594 4334  221  494 2032 1425 2525 3358  791 3691
#> 6 2016-06-01   191 4169  570 3245 1682 3811 4350 2344 4338 2258  779 1835 2480

现在我们有了一些示例数据,我们可以使用双索引来根据月份提取每列的值。我假设月份的名称为V1 - V12(因为它们位于我的数据集中)。

sample.data %>%
    mutate(Z = .[cbind(seq_along(nrow(.)), match(sprintf("V%s", month(date_var)), names(.)))], 
           Z = as.numeric(Z),
           Z = value / Z) ->
    result

head(result)
#>     date_var value   V1   V2   V3   V4   V5   V6   V7   V8   V9  V10  V11  V12          Z
#> 1 2016-01-01   147 2004 2456 3983 4464 2473 2824 2038 1354 3433   51  574 1381 0.07335329
#> 2 2016-02-01   170 2862 3579  543 1458 2472  826 3865  528  187  951 4732 1849 0.06921824
#> 3 2016-03-01   107 2860 1359 4366 1824  173 3541  624   76 4113  771  808 3457 0.02686417
#> 4 2016-04-01   115 1707 4015 3951 2774 2726 1789 2189 1903 1706  124 3679 1876 0.02576165
#> 5 2016-05-01   120 1058 4169 2594 4334  221  494 2032 1425 2525 3358  791 3691 0.04852406
#> 6 2016-06-01   191 4169  570 3245 1682 3811 4350 2344 4338 2258  779 1835 2480 0.06763456

答案 3 :(得分:0)

不是最优雅的方式,但你可以使用for循环(假设这是数据的布局):

data = "yourData"
x = as.numeric(format(data[,1],"%m"))
for (i in 1:length(data[,1])){
data[i,"Z"] = data[i,2]/data[i,x[i]+2]
}