从映射值计算新列

时间:2018-03-14 00:02:52

标签: r

我有一个data.frame df

df = data.frame(v = c('E', 'B', 'EB', 'RM'))
df$n= 100 / apply(df, 1, nchar)

其中v代表值E = 4B = 3R = 2M = 1

我想像这样计算一列:

   v   n idx
1  E 100 400
2  B 100 300
3 EB  50 350
4 RM  50 150

其中idx为n (v)。例如,第一行4 * 100 = 400和最后一行(2 + 1) * 50 = 150

我有这样的事情:

df$e = ifelse(grepl('E', df$v), 4, 0)
df$b = ifelse(grepl('B', df$v), 3, 0)
df$r = ifelse(grepl('R', df$v), 2, 0)
df$m = ifelse(grepl('M', df$v), 1, 0)

df$idx = df$n * (df$e + df$b + df$r + df$m)

但随着列数的增加,它变得不可行。

2 个答案:

答案 0 :(得分:3)

1)定义一个查找表lookup和一个带有单个字母向量的函数Sum,查找每个字母并将它们的查找数相加。

v分成单个字母和sapply的向量列表,使用Sum将结果按n进行操作。

lookup <- c(E = 4, B = 3, R = 2, M = 1)
Sum <- function(x) sum(lookup[x])
transform(df, idx = n * sapply(strsplit(as.character(v), ""), Sum))

,并提供:

   v   n idx
1  E 100 400
2  B 100 300
3 EB  50 350
4 RM  50 150

2)上面使用lookup的替代方法是v中的每个字符使用在公式表示法创建中表示的匿名函数来应用lookup我们sapply sum的列表,最后乘以n

library(gsubfn)
transform(df, idx = n * sapply(strapply(as.character(v), ".", x ~ lookup[x]), sum))

3)以上使用lookup的dplyr / tidyr解决方案如下。我们插入id来唯一标识每一行,并使用separate_rowsv的每个字母放在一个单独的行中。然后,我们通过查找每个字母和求和来汇总具有相同id的所有行。最后,我们删除id

library(dplyr)
library(tidyr)

df %>% 
   mutate(id = 1:n()) %>% 
   separate_rows(v, sep = "(?<=.)(?=.)") %>%
   group_by(id, n) %>%
   summarize(idx = sum(n * lookup[v])) %>%
   ungroup %>%
   select(-id)

,并提供:

# A tibble: 4 x 3
     id     n   idx
  <int> <dbl> <dbl>
1     1  100.  400.
2     2  100.  300.
3     3   50.  350.
4     4   50.  150.

可以通过用这两个语句替换separate_rows语句来避免复杂的正则表达式:

mutate(v = strsplit(as.character(v), "")) %>%
unnest %>%

答案 1 :(得分:1)

使用您的值制作查找表。然后在match列的拆分版本(通过strsplit),df$v相应的值之间sum进行乘法计算:

lkup <- data.frame(id=c("E","B","R","M"),value=c(4,3,2,1))
sapply(
  strsplit(as.character(df$v),""),
  function(x) sum(lkup$value[match(x,lkup$id)])
) * df$n
#[1] 400 300 350 150