【问题标题】:separate data in 2 groups with elements of each pair in separate groups将数据分成 2 组,每对的元素在不同的组中
【发布时间】:2018-02-26 12:25:56
【问题描述】:

我有一个数据集,由两列 player1player2 组成,用于一组 n 个玩家。每 2 名玩家互相玩两次(一次 i 为 player1,j 为 player2,一次 i 为 player2,j 为 player1

我想分离我的数据,以便我有一个 games1 数据框,其中包含两个玩家的第一场比赛的所有游戏和一个数据框 game2,其中包括他们所有的第二场比赛(显然每个子数据框是一半我原始数据框的大小)

我考虑过使用 for 循环遍历所有行并定义一个标志来确定这是否是两个玩家正在玩的第一个游戏。我只是想知道是否有更简单/更快的方法。

我有一个 data.frame()

# reproducible exmaple
df1 <- read.table(text = "player1  player2
1:         1        2
2:         2        3
3:         3        2
4:         1        3
5:         2        1
6:         3        1", header = TRUE)

我需要:

data.frame()
     player1  player2
1:         1        2
2:         2        3
3:         1        3

1:         3        2
2:         2        1
3:         3        1

【问题讨论】:

  • 最终df1$game &lt;- ifelse(df$player1&lt;df$player2, 1, 2) 用于定义分组变量。
  • @jogo 这个例子是偶然的,我的数据是按时间排序的。 3 作为player12 作为player2 之间的游戏可以在2 作为player13 作为3 作为player2 之前进行,所以我必须根据他们的顺序对它们进行分组

标签: r dataframe


【解决方案1】:

一个稍微难看的解决方案可以是按行排序,并通过duplicated(...)duplicate(..., fromLast = TRUE)得到两组,即

d1 <- data.frame(t(apply(df1, 1, function(i) sort(i, decreasing = TRUE))))

df1[!duplicated(d1),]
#   player1 player2
#1:       1       2
#2:       2       3
#4:       1       3

#AND

df1[!duplicated(d1, fromLast = TRUE),]
#   player1 player2
#3:       3       2
#5:       2       1
#6:       3       1

由于不建议在全局环境中保留大量对象,因此可以将它们添加到列表中,即

list1 <- list(df1[!duplicated(d1),], df1[!duplicated(d1, fromLast = TRUE),])

【讨论】:

    【解决方案2】:

    首先你必须确定这两个玩家。然后您可以使用组合进行分组:

    # reproducible exmaple
    df1 <- read.table(text = "player1  player2
    1:         1        2
    2:         2        3
    3:         3        2
    4:         1        3
    5:         2        1
    6:         3        1", header = TRUE)
    df1$players <- with(df1, 
            ifelse(player1 < player2, paste(player1, player2, sep='.'), paste(player2, player1, sep='.')))
    df1$game <- ave(df1$players, df1$players, FUN=function(x) c(1,2))
    # > df1
    #    player1 player2 players game
    # 1:       1       2     1.2    1
    # 2:       2       3     2.3    1
    # 3:       3       2     2.3    2
    # 4:       1       3     1.3    1
    # 5:       2       1     1.2    2
    # 6:       3       1     1.3    2
    

    这是data.table的解决方案:

    library("data.table")
    # reproducible exmaple
    df1 <- read.table(text = "player1  player2
    1:         1        2
    2:         2        3
    3:         3        2
    4:         1        3
    5:         2        1
    6:         3        1", header = TRUE)
    setDT(df1)
    df1[, players:=ifelse(player1 < player2, paste(player1, player2, sep='.'), paste(player2, player1, sep='.'))]
    df1[, game:=c(1,2), players][]
    

    使用函数rowid() 可以缩短为(感谢@Frank):

    df1[, game := rowid(paste(pmin(player1, player2), pmax(player1, player2)))]
    

    可以在两个变体中通过来自基 R 的函数 split() 来完成组的拆分:

    split(df1, by="game", keep = FALSE)
    

    结果将是两个 data.table-objects 的列表。

    【讨论】:

    • 重新data.table,也可以做df1[, match := rowid(paste(pmin(player1, player2), pmax(player1, player2)))]; split(df1, by="match", keep = FALSE)
    【解决方案3】:

    稍微干净的解决方案:

      df2
           player1 player2
        1:       1       2
        2:       3       2
        3:       2       3
        4:       1       3
        5:       2       1
        6:       3       1
    
    game1<-df2[!duplicated(t(apply(df2, 1, sort))),]
    
     game1
      #     player1 player2
      #  1:       1       2
      #  2:       3       2
      #  4:       1       3
    
    game2<-setdiff(df2,game1)
    
    game2
     #     player1 player2
     #  1       2       3
     #  2       2       1
     #  3       3       1
    

    【讨论】:

      猜你喜欢
      • 2016-09-25
      • 1970-01-01
      • 1970-01-01
      • 2019-08-14
      • 2020-12-27
      • 1970-01-01
      • 1970-01-01
      • 2021-02-09
      • 2019-12-25
      相关资源
      最近更新 更多