【问题标题】:Getting net values as a proportion from a dataframe in R从R中的数据框中获取净值作为比例
【发布时间】:2018-06-23 11:25:39
【问题描述】:

我在 R (p2.df) 中有一个数据框,它已将一系列值汇总到以下内容中(还有更多列,这只是一个精简版本):

genre       rating  cc      dd      ee
Adventure   FAILURE 140393  20865   358806
Adventure   SUCCESS 197182  32872   492874
Fiction     FAILURE 140043  14833   308602
Fiction     SUCCESS 197725  28848   469879
Sci-fi      FAILURE 8681    1682    24259
Sci-fi      SUCCESS 7439    1647    22661

我想获得每列比例的净值,我可以在电子表格中获得,但不能在 R Studio 中获得。

电子表格中的公式遵循以下模式:

net_cc = (cc(success)/(cc(success)+dd(success)+ee(success)) - (cc(fail)/(cc(fail)+dd(fail)+ee(fail))

我想在 R 中得到的是可以从电子表格中得到的这张表:

genre       net_cc          net_dd          net_ee
Adventure   0.002801373059  0.005350579467  -0.008151952526
Fiction     -0.01825346696  0.009417699223  0.008835767735
Sci-fi      -0.01641517271  0.003297091109  0.0131180816

有什么想法吗?如果有任何用处,我通过将以前的表格总结为以下形式创建了 p2.df:

library(dplyr)

p2.df<- s2.df %>% group_by(genre,rating) %>% summarise_all(sum)  

【问题讨论】:

  • 谢谢大家,我选择 Moody's 作为答案,因为它是最简单的(我无法让 utubun 更整洁),但 MKR 也可以。
  • ...然后它停止工作。我认为这是因为我使用 'summarise_at' 来获取上述数据框,它不喜欢与组合作。
  • 这可能是因为您通过data.frame() 创建数据集或通过read.csv() 读取数据集,默认情况下会将字符串转换为因子。我使用将ratinggenre 转换为character 的数据编写了我的示例,这是tibleread_csv 来自readr 的默认值。请查看@MKR 在他的回答中使用的数据(最后一行 - stringsAsFactors = FALSE)。
  • 谢谢你是对的,表格有分组,所以我添加了 as.data.frame() 来修复它。

标签: r dataframe dplyr


【解决方案1】:

处理长格式数据总是更好。但是,如果 OP 由于任何限制(例如,列数更多,这将导致大量行长格式等)而不想以长格式转换数据,那么使用dplyr::summarise_at 的解决方案可以实现为:

library(dplyr)

df %>% mutate(rowSum = rowSums(.[,names(df)[3:5]])) %>%
  group_by(genre) %>%
  summarise_at(vars(names(df)[3:5]),
              funs(net = .[rating == "SUCCESS"]/rowSum[rating == "SUCCESS"] - 
                         .[rating == "FAILURE"]/rowSum[rating == "FAILURE"] )) %>%
  as.data.frame()

#       genre       cc_net      dd_net       ee_net
# 1 Adventure  0.002801373 0.005350579 -0.008151953
# 2   Fiction -0.018253467 0.009417699  0.008835768
# 3    Sci-fi -0.016415173 0.003297091  0.013118082

数据:

df <- read.table(text="
genre       rating  cc      dd      ee
Adventure   FAILURE 140393  20865   358806
Adventure   SUCCESS 197182  32872   492874
Fiction     FAILURE 140043  14833   308602
Fiction     SUCCESS 197725  28848   469879
Sci-fi      FAILURE 8681    1682    24259
Sci-fi      SUCCESS 7439    1647    22661",
header = TRUE, stringsAsFactors = FALSE)

【讨论】:

  • 这是一个简洁直观的解决方案,但您可以进一步清理它,您可以在第一行使用rowSums(.[,3:5]),然后使用summarise_at(3:5,...
  • @Moody_Mudskipper 这是优雅的建议。我一开始也是这样做的。但是,问题在于,对于summarise_at,它应该是2:4,因为有一列用于分组。因此,我认为如果我在两个地方都使用3:5 会更容易关联。
  • 这可能与不同版本有关,对我来说它适用于 3:5 并返回错误 2:4 。我正在使用 dplyr_0.7.5
  • 感谢您在此方面的帮助,您说最好以长格式工作,我很乐意这样做,因为这些解决方案似乎对我有气质 - 当我将它们扩展为我自己的摘要时table 有时它可以工作,有时它会告诉我找不到对象(列名)或 Column rowSum 的长度必须为 2(组大小)或 1,而不是 16。也许我应该尝试长形式而不是从汇总表。
【解决方案2】:

使用tidyverse:

library(tidyverse)
df %>% gather(,,3:5) %>%
  spread(rating,value) %>%
  group_by(genre) %>%
  transmute(key,net = SUCCESS/sum(SUCCESS) - FAILURE/sum(FAILURE)) %>%
  ungroup %>%
  spread(key,net)

# # A tibble: 3 x 4
# genre           cc      dd       ee
#   <chr>        <dbl>   <dbl>    <dbl>
# 1 Adventure  0.00280 0.00535 -0.00815
# 2 Fiction   -0.0183  0.00942  0.00884
# 3 Sci-fi    -0.0164  0.00330  0.0131 

【讨论】:

    【解决方案3】:

    我的答案与@MKR 的答案非常接近,但是,我只想指出,我们可以利用解码的ratingSUCESS = 1FAILURE = -1`)变量来避免在最后一部分:

    df %>% 
      mutate(rating = (rating == "SUCCESS")*2 - 1, denom = rowSums(.[3:5])) %>%
      group_by(genre) %>%
      summarise_at(vars(cc:ee), funs(sum(rating * . / denom)))
    
       #   A tibble: 3 x 4
       #   genre           cc      dd       ee
       #   <chr>        <dbl>   <dbl>    <dbl>
       # 1 Adventure  0.00280 0.00535 -0.00815
       # 2 Fiction   -0.0183  0.00942  0.00884
       # 3 Sci-fi    -0.0164  0.00330  0.0131 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多