【问题标题】:Sum data points in the rows from data frame if they meet criteria from another data frame in R如果数据帧符合 R 中另一个数据帧的标准,则对数据帧中的行中的数据点求和
【发布时间】:2018-05-20 18:11:49
【问题描述】:

我有两个包含 220 个 obs 和 80 个变量的数据框。第一个数据帧df1 仅包含数据点123。第二个数据框df2 具有不同的由小数组成的数值,例如0.12-0.030.01 等(旨在描述给定月份的市值加权股票收益)。 PS:原始数据集长度为80。

例如

df1 = data.frame(a = c(2, 2, 1), b = c(3, 2, 3), c = c(1, 1, 2), d = c(3, 3, 1))

  a b c d
1 2 3 1 3
2 2 2 1 3
3 1 3 2 1

df2 = data.frame(a = c(0.1, 0.1, 0.2), b = c(0.3, 0.4, 0.6), c = c(0.2, 0.3, 0.5), d = c(0.1, 0.5, 0.6))

    a   b   c   d
1 0.1 0.3 0.2 0.1
2 0.1 0.4 0.3 0.5
3 0.2 0.6 0.5 0.6

如何对df2 的行求和,然后根据df1 中的值转换成一个包含 220 个 obs 和 3 个变量的矩阵。请注意,df1df2 具有相同的列名,顺序相同。如何通过对df2 的行求和,基于来自df1 的指标变量创建第三个数据框df3?我想根据df1 中的值对df2 的行求和以创建df3

df3 =
   X1  X2  X3
1 0.2 0.1 0.4
2 0.3 0.5 0.5
3 0.8 0.5 0.6

我们先来看看(X1,1)。在df1 中的行1 只包含一个值为1 的数据点,即(c,1)。因此,我们将df2 的行1 相加得到0.2。现在查看(X1,3)X1 列的最后一个值)。观察df1 中的行3 以找到两个值为1 的数据点。在df2 中,这两个值是0.2 (a,3)0.6 (d,3),并将这些值相加得到0.8

下面是df3 的解释:

calculation = data.frame("1" = c("0+0+0.2+0", "0+0+0.3+0", "0.2+0+0+0.6"), "2" = c("0.1+0+0+0", "0.1+0.4+0+0", "0+0+0.5+0"), "3" = c("0+0.3+0+0.1", "0+0+0+0.5", "0+0.6+0+0"))

                 X1                X2                X3
1   0 + 0 + 0.2 + 0   0.1 + 0 + 0 + 0 0 + 0.3 + 0 + 0.1
2   0 + 0 + 0.3 + 0 0.1 + 0.4 + 0 + 0   0 + 0 + 0 + 0.5
3 0.2 + 0 + 0 + 0.6   0 + 0 + 0.5 + 0   0 + 0.6 + 0 + 0

基于股票的更实用的解释。假设df1 是一个描述买入、持有和卖出建议的矩阵。 df2 描述了市场加权股票收益。所有变量/列都是不同的库存。 df3 创建一个包含三个不同投资组合的矩阵。如果股票是“买入”,我想将其放入“买入”投资组合。如果股票是“持有”,我想把它放在一个“持有”的投资组合中,等等。这很容易在 Excel 中使用嵌套的IF,AND,OR 函数完成,但我不知道如何在 R 中做。

【问题讨论】:

    标签: r if-statement dataframe sum rows


    【解决方案1】:

    我们可以通过将数据集转换为matrix来使用tapply,使用分组变量作为数据的row索引和'df1'的索引

    tapply(as.matrix(df2), list(row(df2), as.matrix(df1)), FUN = sum)
    #       1   2   3
    #[1,] 0.2 0.1 0.4
    #[2,] 0.3 0.5 0.5
    #[3,] 0.8 0.5 0.6
    

    或者用tidyverse,将gather之后的数据集绑定成'long'数据,然后通过sum做一个分组

    library(tidyverse)
    gather(df1) %>%
        bind_cols(gather(df2)) %>% 
        group_by(key) %>%
        group_by(rn = row_number(), value) %>% 
        summarise(value1 = sum(value1)) %>% 
        spread(value, value1) %>% 
        ungroup %>% 
        select(-rn)
    # A tibble: 3 x 3
    #    `1`   `2`   `3`
    #  <dbl> <dbl> <dbl>
    #1   0.2   0.1   0.4
    #2   0.3   0.5   0.5
    #3   0.8   0.5   0.6
    

    【讨论】:

    • 我为我的数据集尝试了 tapply,但它给了我 5 个数组而不是 3 个。这有什么原因吗?
    • @Mataunited17 是的,唯一的原因是原始数据的长度不相等,而示例中的长度相同
    • 我明白了。 df1df2 的原始数据长度均为 80。
    • @Mataunited17 我的意思是每行 'df1' 元素的频率
    • 我现在明白了。我不得不删除所有的 0s 和 4s 使其变成 5 个数组而不是 3 个。感谢您的帮助!
    【解决方案2】:

    这是另一种基本 R 方法,它使用 rowsum 执行组求和并循环使用 mapply 的行。

    t(mapply(rowsum, as.data.frame(t(df2)), as.data.frame(t(df1))))
       [,1] [,2] [,3]
    V1  0.2  0.1  0.4
    V2  0.3  0.5  0.5
    V3  0.8  0.5  0.6
    

    请注意,我使用的是 R 3.4.4。我相信 as.data.frame 对于 R 3.5.0+ 来说不是必需的,因为 t 在输入 data.frame 时应该返回一个 data.frame。

    【讨论】:

    • 不错的选择。我也在考虑rowsum
    • 这需要多次转置,但对于中等大小的数据应该不会太糟糕。
    • @lmo 这在我的原始数据集中不起作用。它只是给了我一个行向量,每个数据点都有多个字符向量。
    • 我的猜测是你的一些变量是字符。转置会将 data.frame 转换为字符矩阵。我怀疑rowsum 会出错,但是如果没有看到您的原始数据,很难诊断。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 2021-08-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多