我已经在堆栈溢出方面进行了广泛的研究,但是找不到任何对我想要的输出有用的东西。
为说明起见,请考虑以下示例数据框:
D X Y Z A B C Total
1 abc 2 3 4 7 2 1 19
总计对应于每一行的总和。为了简单起见,让B = 19,这是总数。我想要的输出是:
D X Y Z A B C Total
1 abc 1 2 3 4 5 2 B
2 N/A 1/B 2/B 3/B 4/B 5/B 2/B 1
在这里,第一行中的每个元素都除以总数,这反映在第二行中。为了创建总计列,我使用了mutate并做到了:
df <- df %>% mutate(Total = X + Y + Z + A + B + C)
但是我无法弄清楚如何创建一个行,其中每个元素都可以被总数除。
任何帮助将不胜感激!在执行此操作时,我不介意使用mutate或data.table,因为我使用data.table创建了一个大数据框。
EDIT1:非常抱歉没有提及此内容,但是一列中包含一些字符串。我已经编辑了上面的内容以反映这一点。
答案 0 :(得分:1)
我又增加了一行以使解决方案更通用。
在基数R中,我们可以将数据帧除以该行中的Total
列,然后将其与原始数据帧rbind
分开。
new_df <- rbind(df, df/df[, "Total"])
new_df
# X Y Z A B C Total
#1 2.0000000 3.0000000 4.0000000 7.0000000 2.0000000 1.00000000 19
#2 1.0000000 2.0000000 5.0000000 6.0000000 7.0000000 4.00000000 25
#11 0.1052632 0.1578947 0.2105263 0.3684211 0.1052632 0.05263158 1
#21 0.0400000 0.0800000 0.2000000 0.2400000 0.2800000 0.16000000 1
如果订单很重要并且您想要维护它,那么我们可以重新订购
rbind(new_df[c(T, F),], new_df[c(F, T),])
# X Y Z A B C Total
#1 2.0000000 3.0000000 4.0000000 7.0000000 2.0000000 1.00000000 19
#11 0.1052632 0.1578947 0.2105263 0.3684211 0.1052632 0.05263158 1
#2 1.0000000 2.0000000 5.0000000 6.0000000 7.0000000 4.00000000 25
#21 0.0400000 0.0800000 0.2000000 0.2400000 0.2800000 0.16000000 1
编辑
如果某些列是字符串,我们可以忽略它们,并使用bind_rows
代替rbind
,因为它会直接为不匹配的列返回NA
。
library(dplyr)
bind_rows(df1, df1[!names(df1) %in% "D"]/df1[, "Total"])
# X Y Z A B C Total D
#1 2.0000000 3.0000000 4.0000000 7.0000000 2.0000000 1.00000000 19 abc
#2 1.0000000 2.0000000 5.0000000 6.0000000 7.0000000 4.00000000 25 def
#3 0.1052632 0.1578947 0.2105263 0.3684211 0.1052632 0.05263158 1 <NA>
#4 0.0400000 0.0800000 0.2000000 0.2400000 0.2800000 0.16000000 1 <NA>
数据
df <- structure(list(X = c(2, 1), Y = c(3, 2), Z = c(4, 5), A = c(7,
6), B = c(2, 7), C = c(1, 4), Total = c(19, 25)), .Names = c("X",
"Y", "Z", "A", "B", "C", "Total"), row.names = c("1", "2"), class = "data.frame")
df1 <-structure(list(X = c(2, 1), Y = c(3, 2), Z = c(4, 5), A = c(7,
6), B = c(2, 7), C = c(1, 4), Total = c(19, 25), D = c("abc",
"def")), .Names = c("X", "Y", "Z", "A", "B", "C", "Total", "D"
), row.names = c("1", "2"), class = "data.frame")
答案 1 :(得分:1)
这是您问题的dplyr
答案。您实际上想要做的事情可能会更复杂,但是此简单的bind_rows
,filter
和mutate_all
适用于所提供的简单示例。
library(dplyr)
df <- data.frame(x = 2:3, y = 3:4, z = letters[1:2], total = c(0, 19))
bind_rows(
df,
filter(df, row_number() == n()) %>%
mutate_if(is.numeric, funs(. / total))
)
# x y z total
# 1 2.0000000 3.0000000 a 0
# 2 3.0000000 4.0000000 b 19
# 3 0.1578947 0.2105263 b 1