我有一个数据框,其中包含一个日期列,一列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
,虽然这返回列表而不是按元素工作,因此显然不是正确的方法。
答案 0 :(得分:2)
使用dplyr
和tidyr
软件包的另一个好方法基本上采用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]
}