在R中按子串乘以列

时间:2018-06-18 18:57:58

标签: r dataframe substr

假设我有一个数据框,其中有多个组件,并且它们的属性列在多列中,我想对列运行多个函数。我的方法是尝试将其基于每个列标题中的子字符串,但我还没有能够弄清楚如何做到这一点。以下是数据框的示例。

Basket   F_Type_1   F_Qty_1   F_P_1   F_Type_2   F_Qty_2   F_P_2 
AAA       Apple     10        2.5     Banana     9         2
BBB       Peach     5         6       Melon      20        5

我基本上想要在这个数据帧的末尾添加两个新列,它们将Qty和P相乘,这样你就会得到两个新的列,如下所示。

F_Total_1   F_Total_2
25          18
30          100

输入是动态的,所以有时它可能是2个水果或10个水果在某些篮子里。但是我可以把这个部分弄清楚,它还试图找出如何根据子串#1'来计算列数。或者' 2'。

感谢您的所有帮助以及您可能采取的任何其他方法!

6 个答案:

答案 0 :(得分:2)

我们创建一个查找特定名称的函数,然后计算rowwise产品。这个函数的重要提升者是mapply函数。我们添加了最后一步来重命名结果[@-1,0:0='<',<7>,1:0] [@-1,1:4='item',<16>,1:1] [@-1,5:5='>',<10>,1:5] [@-1,6:8='\n ',<6>,1:6] [@-1,9:42='<![CDATA[',<2>,2:2] [@-1,9:42='\n My CDATA Block\n ',<19>,2:2] [@-1,9:42=']]>',<18>,2:2] [@-1,43:43='\n',<6>,4:5] [@-1,44:44='<',<7>,5:0] [@-1,45:45='/',<13>,5:1] [@-1,46:49='item',<16>,5:2] [@-1,50:50='>',<10>,5:6]

data.frame

答案 1 :(得分:1)

创建数据

library(data.table)
df <- fread("
Basket   F_Type_1   F_Qty_1   F_P_1   F_Type_2   F_Qty_2   F_P_2 
AAA       Apple     10        2.5     Banana     9         2
BBB       Peach     5         6       Melon      20        5
")

df
#    Basket F_Type_1 F_Qty_1 F_P_1 F_Type_2 F_Qty_2 F_P_2
# 1:    AAA    Apple      10   2.5   Banana       9     2
# 2:    BBB    Peach       5   6.0    Melon      20     5

对于从1到sum(grepl('F_P_', names(df)))的数字,请将F_Total_{number}设为F_Qty_{number}*F_P_{number}

for(i in seq(sum(grepl('F_P_', names(df)))))
  df[, paste0('F_Total_', i) := Reduce(`*`, .SD)
     , .SDcols = paste0(c('F_Qty_', 'F_P_'), i)]

df
#    Basket F_Type_1 F_Qty_1 F_P_1 F_Type_2 F_Qty_2 F_P_2 F_Total_1 F_Total_2
# 1:    AAA    Apple      10   2.5   Banana       9     2        25        18
# 2:    BBB    Peach       5   6.0    Melon      20     5        30       100

或在基数R中,dfdata.frame

for(i in seq(sum(grepl('F_P_', names(df)))))
  df[paste0('F_Total_', i)] <- Reduce(`*`, df[paste0(c('F_Qty_', 'F_P_'), i)])

答案 2 :(得分:1)

在基础R中,您可以使用[[]]表单来访问带字符串的列,这样您就可以轻松循环

df <- read.table(text = "Basket   F_Type_1   F_Qty_1   F_P_1   F_Type_2   F_Qty_2   F_P_2 
AAA       Apple     10        2.5     Banana     9         2
BBB       Peach     5         6       Melon      20        5",header = T)

for(i in 1:2)
{
  df[[paste0("F_Total_",i)]] <- as.numeric(df[[paste0("F_P_",i)]])*as.numeric(df[[paste0("F_Qty_",i)]])
}

  Basket F_Type_1 F_Qty_1 F_P_1 F_Type_2 F_Qty_2 F_P_2 F_Total_1 F_Total_2
1    AAA    Apple      10   2.5   Banana       9     2        25        18
2    BBB    Peach       5   6.0    Melon      20     5        30       100

答案 3 :(得分:1)

这是一种使用tidyverse函数重塑数据的方法。基本上使用tidyr动词,我们将您的数据重塑为更“整洁”的格式。

# library(dplyr); library(tidyr)
dd %>% select(Basket, contains("_Qty_"), contains("_P_")) %>% 
  gather("key", "value", -Basket) %>% 
  separate(key, c("F", "Val", "Grp")) %>% 
  group_by(Basket, Grp) %>% 
  spread(Val, value) %>% 
  mutate(Total=P*Qty, GrpN=paste0("Total_", Grp)) %>% 
  ungroup() %>% 
  select(Basket, GrpN, Total) %>% 
  spread(GrpN ,Total)

#   Basket Total_1 Total_2
#   <fct>    <dbl>   <dbl>
# 1 AAA         25      18
# 2 BBB         30     100

答案 4 :(得分:1)

setNames(df[grepl("F_Qty",names(df))]*df[grepl("F_P",names(df))],paste0("F_Total_",1:2))

  F_Total_1 F_Total_2
1        25        18
2        30       100

答案 5 :(得分:0)

建议:如果您可以以长格式存储数据,它将使未来的维护更加清洁。

Basket     Item     Type    Qty Price    Total
AAA           1    Apple     10   2.5       25
AAA           2    Banana     9     2       18
BBB           1    Peach      5   6.0       30
BBB           2    Melon     20     5      100
BBB           3    Orange    11   2.7     29.7

然后,当您确实需要上述格式的数据时,请使用data.table包来转置数据。

library(data.table)
fruits <- data.frame("Basket" = c("AAA", "AAA", "BBB", "BBB", "BBB"),
                 "Item" = c(1,2,1,2,3),
                 "Type" = c("Apple", "Banana", "Peach", "Melon", "Orange"),
                 "Qty" = c(10, 9, 5, 20, 11),
                 "Price" = c(2.5, 2, 6.0, 5, 2.7)
)

fruits$Total <- fruits$Qty * fruits$Price
fruits.New <- data.table::dcast(setDT(fruits),
                            formula = Basket ~ Item,
                            value.var = c("Type", "Price", "Qty", "Total"))

这样,您只需维护一个公式而不必担心apply,同时也可以灵活地使用可变列号。

如果列名称很重要,则应该相对容易修复。