【问题标题】:Cumulative count of names from two separate columns来自两个单独列的名称的累积计数
【发布时间】:2017-07-27 13:59:49
【问题描述】:

我有一个按时间顺序排列的数据集,我已使用以下方法将其导入 R:

mydata <- read.csv(file="test.csv",stringsAsFactors=FALSE)

数据集中的两列是“赢家”和“输家”。数据中的每一行都是一场网球比赛。

我想要做的是添加两列,这可以让我计算出“获胜者”列中的玩家已经玩过的总匹配数,包括该行的匹配数。并且该行中的“失败者”的计数相同。

例如,它看起来像这样:

winner loser winner_matches loser_matches
tom    andy        1             1
andy   greg        2             1
greg   tom         2             2

我希望这是有道理的。

我已尝试使用以下代码,但无法使其在两列中都起作用:

ave(mydata$winner_name==mydata$winner_name, mydata$winner_name, FUN=cumsum)

所以下面的数据是前10行20000左右。

【问题讨论】:

  • 你的预期输出是多少
  • 所以目前winner_matches 和loser_matches 列不在我的数据中,它们是我想要通过累计计算两列中的名称来实现的目标
  • 好的,你介意分享一下当前的mydata 是什么样的吗?
  • @Masoud 您不应该根据答案添加标签。它们应该只与问题有关。我认为这里不需要dataframe,另外两个也不会出现在问题中。
  • @Frank 我对此略有不同意见。有元帖子谈论这个问题。当然标签不应该基于答案,但我认为这属于其中的例外。仍然是一个有争议的事情。我将在您的最新编辑中留下问题。干杯。

标签: r


【解决方案1】:

1) base 定义一个函数,该函数将指定玩家的匹配计数直到第 i 行,然后将其分别应用于获胜者和失败者的比赛。没有使用任何包:

count_matches <- function(i, player) {
    with(DF[1:i, ], sum(winner == player | loser == player))
}
n <- nrow(DF)
transform(DF, winner_matches = mapply(count_matches, 1:n, winner),
              loser_matches = mapply(count_matches, 1:n, loser))

给予:

  winner loser winner_matches loser_matches
1    tom  andy              1             1
2   andy  greg              2             1
3   greg   tom              2             2

2) sqldf 在意识到这个问题可以在这样的复杂条件下通过自连接解决时,可以使用 sqldf 获得不同的解决方案:

library(sqldf)
sqldf("select a.winner, 
              a.loser, 
              sum(a.winner = b.winner or a.winner = b.loser) winner_matches,
              sum(a.loser = b.winner or a.loser = b.loser) loser_matches
       from DF a join DF b on a.rowid >= b.rowid
       group by a.rowid")

给予:

  winner loser winner_matches loser_matches
1    tom  andy              1             1
2   andy  greg              2             1
3   greg   tom              2             2

注意:所使用的输入,以可重现的形式,是:

Lines <- "winner loser 
tom    andy
andy   greg
greg   tom"
DF <- read.table(text = Lines, header = TRUE, as.is = TRUE)

【讨论】:

    【解决方案2】:

    我们可以通过data.table包获取每个玩家输赢的次数:

    library(data.table)
    setDT(dat)[, winner_matches_won := seq_len(.N), by=(winner)]
    setDT(dat)[, loser_matches_lost := seq_len(.N), by=(loser)]
    
    dat
    
    #    winner loser winner_matches_won loser_matches_lost 
    # 1:    tom  andy                  1                  1 
    # 2:   andy  greg                  1                  1 
    # 3:   greg   tom                  1                  1 
    # 4:   greg   tom                  2                  2 
    # 5:    tom  greg                  2                  2
    

    数据:

    dat <- structure(list(winner = structure(c(3L, 1L, 2L, 2L, 3L), .Label = c("andy", 
                                                                               "greg", "tom"), class = "factor"), loser = structure(c(1L, 2L, 
                                                                                                                                      3L, 3L, 2L), .Label = c("andy", "greg", "tom"), class = "factor")), .Names = c("winner", 
                                                                                                                                                                                                                     "loser"), class = "data.frame", row.names = c(NA, -5L))
    

    【讨论】:

    • 我会做DT = melt(setDT(DF)[, match := .I], id="match", measure.vars = patterns("^(winner|loser)$"), variable.name = "outcome", value.name = "name"); DT[order(match), nth_match := rowid(name)] 或类似的。我猜你可以使用dcast 从那里回到 OP 的(坏)宽格式。
    • @Frank 谢谢弗兰克。这以某种方式弄乱了订单(不是真的)。但你是对的。我可以得到宽幅格式。
    【解决方案3】:

    您真的很接近让ave 工作了。 cumsum 函数不知道如何处理文本,所以我为每一行创建了一个等于 1 的虚拟列。这让cumsum 有了一些重要的意义。

    这是一个示例数据框。

    mydata <-
      data.frame(
        winner = c("tom", "andy", "greg", "tom", "gary"),
        loser = c("andy", "greg", "tom", "gary", "tom"),
        stringsAsFactors = FALSE
      )
    

    这是添加两个新列的代码。

    library(tidyverse)
    
    mydata <- mutate(mydata, one = 1) # Add dummy column
    
    # Use ave() to calculate both the wins and losses
    mydata$winner_matches <- ave(x = mydata$one, mydata$winner, FUN = cumsum)
    mydata$loser_matches  <- ave(x = mydata$one, mydata$loser, FUN = cumsum)
    
    mydata <- select(mydata, -one) # Remove dummy column
    

    【讨论】:

    • 该问题询问获胜者和失败者分别参加的比赛次数,但这并没有给出。
    • @G.Grothendieck 是的。它提供输家和赢家赢得和输掉的比赛数量。喜欢我的回答。
    • 它给出了赢家赢得的比赛数和输家输掉的比赛数量,但问题要求赢家参加的比赛数量和失败者参加的比赛数量。
    猜你喜欢
    • 2019-07-08
    • 1970-01-01
    • 1970-01-01
    • 2016-03-28
    • 2018-12-05
    • 2022-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多