数据表创建行

时间:2018-10-12 01:12:41

标签: r dplyr data.table mutate

我已经在堆栈溢出方面进行了广泛的研究,但是找不到任何对我想要的输出有用的东西。

为说明起见,请考虑以下示例数据框:

      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:非常抱歉没有提及此内容,但是一列中包含一些字符串。我已经编辑了上面的内容以反映这一点。

2 个答案:

答案 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_rowsfiltermutate_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