Đặt R data.table thứ tự hàng bằng cách xâu 2 cột


8

Tôi đang cố gắng tìm ra cách đặt hàng bảng dữ liệu R dựa trên chuỗi 2 cột.

Đây là dữ liệu mẫu của tôi.

dt <- data.table(id = c('A', 'A', 'A', 'A', 'A')
         , col1 = c(7521, 0, 7915, 5222, 5703)
         , col2 = c(7907, 5703, 8004, 7521, 5222))

   id col1 col2
1:  A 7521 7907
2:  A    0 5703
3:  A 7915 8004
4:  A 5222 7521
5:  A 5703 5222

Tôi cần thứ tự hàng để bắt đầu với col1 = 0. Giá trị col1 ở hàng 2 phải bằng giá trị của col2 ở hàng trước, v.v.

Ngoài ra, thường phải luôn có một giá trị khớp để xâu chuỗi thứ tự hàng. Nhưng nếu không, cần chọn giá trị gần nhất (xem hàng 4 & 5 bên dưới).

Kết quả tôi đang tìm kiếm được hiển thị dưới đây:

   id col1 col2
1:  A    0 5703
2:  A 5703 5222
3:  A 5222 7521
4:  A 7521 7907
5:  A 7915 8004

Tôi nghĩ rằng tôi có thể viết một hàm điên để làm điều này .. nhưng tôi tự hỏi liệu có một giải pháp dữ liệu thanh lịch.

EDIT
Tôi đã cập nhật bảng để bao gồm một ID bổ sung với các hàng trùng lặp và một cột nguồn duy nhất:

dt <- data.table(id = c('A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B')
               , col1 = c(7521, 0, 7915, 5222, 5703, 1644, 1625, 0, 1625, 1625)
               , col2 = c(7907, 5703, 8004, 7521, 5222, 1625, 1625, 1644, 1625, 1505)
               , source = c('c', 'b', 'a', 'e', 'd', 'y', 'z', 'x', 'w', 'v'))

    id col1 col2 source
 1:  A 7521 7907      c
 2:  A    0 5703      b
 3:  A 7915 8004      a
 4:  A 5222 7521      e
 5:  A 5703 5222      d
 6:  B 1644 1625      y
 7:  B 1625 1625      z
 8:  B    0 1644      x
 9:  B 1625 1625      w
10:  B 1625 1505      v

Có thể có các giá trị khớp trong một ID. Xem B, hàng 7 & 9 ở trên. Tuy nhiên, có một nguồn duy nhất cho mỗi hàng nơi dữ liệu này đến từ.

Đầu ra mong muốn sẽ là:

    id col1 col2 source
 1:  A    0 5703      b
 2:  A 5703 5222      d
 3:  A 5222 7521      e
 4:  A 7521 7907      c
 5:  A 7915 8004      a
 6:  B    0 1644      x
 7:  B 1644 1625      y
 8:  B 1625 1625      w
 9:  B 1625 1625      z
10:  B 1625 1625      v

Trong đầu ra, các hàng khớp nhau, 8 & 9 có thể theo bất kỳ thứ tự nào.

Cảm ơn!


Sẽ col2có bản sao trong một ID? Ví dụ của bạn sẽ hoạt động như bình thường nhưng nếu có thêm hàng nào, col2sẽ là 1625 hoặc không khớp.
Cole

Đúng. Không phải cái gì tôi nghĩ đến. Xem bài chỉnh sửa để biết thêm chi tiết dữ liệu.
AlexP

Câu trả lời:


3

Đây là một cách tiếp cận khác:

  1. Sắp xếp lại dữ liệu sẽ đặt giá trị 0 trước.
  2. Vòng lặp thông qua phần còn lại của các giá trị để trả về chỉ số của nơi col2phù hợp col1.
setorder(dt, col1)

neworder = seq_len(nrow(dt))
init = 1L
col1 = dt[['col1']]; col2 = dt[['col2']]

for (i in seq_along(neworder)[-1L]) {
  ind = match(col2[init], col1)
  if (is.na(ind)) break
  neworder[i] = init = ind
}

dt[neworder]

##       id  col1  col2
##   <char> <num> <num>
##1:      A     0  5703
##2:      A  5703  5222
##3:      A  5222  7521
##4:      A  7521  7907
##5:      A  7915  8004

Nếu bạn đang thực hiện với nhóm, bạn có thể gói vòng lặp trong a dt[, .I[{...}, by = id]$V1để trả về các chỉ số. Hoặc để làm cho nó trông tốt hơn, chúng ta có thể thực hiện một chức năng.

recursive_order = function (x, y) {
  neworder = seq_len(length(x))
  init = 1L

  for (i in neworder[-1L]) {
    ind = match(y[init], x)
    if (is.na(ind)) break

    # Multiple matches which means all the maining matches are the same number
    if (ind == init) { 
      inds = which(x %in% y[init])
      l = length(inds)
      neworder[i:(i + l - 2L)] = inds[-1L]
      break
    }
    neworder[i] = init = ind
  }
  return(neworder)
}

dt <- data.table(id = c('A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B')
                 , col1 = c(7521, 0, 7915, 5222, 5703, 1644, 1625, 0, 1625, 1625)
                 , col2 = c(7907, 5703, 8004, 7521, 5222, 1625, 1625, 1644, 1625, 1505)
                 , source = c('c', 'b', 'a', 'e', 'd', 'y', 'z', 'x', 'w', 'v'))

setorder(dt, col1)
dt[dt[, .I[recursive_order(col1, col2)], by = id]$V1]

       id  col1  col2 source
    <char> <num> <num> <char>
 1:      A     0  5703      b
 2:      A  5703  5222      d
 3:      A  5222  7521      e
 4:      A  7521  7907      c
 5:      A  7915  8004      a
 6:      B     0  1644      x
 7:      B  1644  1625      y
 8:      B  1625  1625      z
 9:      B  1625  1625      w
10:      B  1625  1505      v

Những công việc này! Tôi vẫn cần hiểu điều này tốt hơn một chút, nhưng kết quả tốt. Bạn sẽ phải làm gì nếu cột 'id' có nhiều giá trị hơn? Giả sử nó có id 'b' và 'c' với các giá trị tương ứng của riêng họ?
AlexP

@AlexP vui lòng xem chỉnh sửa. Điều này phù hợp với đầu ra dự kiến ​​của bạn về câu hỏi sửa đổi của bạn.
Cole

7

Đây là một tùy chọn sử dụng igraphvới data.table:

#add id in front of cols to distinguishes them as vertices
cols <- paste0("col", 1L:2L)
dt[, (cols) := lapply(.SD, function(x) paste0(id, x)), .SDcols=cols]

#permutations of root nodes and leaf nodes
chains <- dt[, CJ(root=setdiff(col1, col2), leaf=setdiff(col2, col1)), id]

#find all paths from root nodes to leaf nodes
#note that igraph requires vertices to be of character type
library(igraph)
g <- graph_from_data_frame(dt[, .(col1, col2)])
l <- lapply(unlist(
  apply(chains, 1L, function(x) all_simple_paths(g, x[["root"]], x[["leaf"]])), 
  recursive=FALSE), names)
links <- data.table(g=rep(seq_along(l), lengths(l)), col1=unlist(l))

#look up edges
dt[links, on=.(col1), nomatch=0L]

đầu ra:

    id  col1  col2 source g
 1:  A    A0 A5703      b 1
 2:  A A5703 A5222      d 1
 3:  A A5222 A7521      e 1
 4:  A A7521 A7907      c 1
 5:  A A7915 A8004      a 2
 6:  B    B0 B1644      x 3
 7:  B B1644 B1625      y 3
 8:  B B1625 B1625      z 3
 9:  B B1625 B1625      w 3
10:  B B1625 B1505      v 3

dữ liệu:

library(data.table)
dt <- data.table(id = c('A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B')
  , col1 = c(7521, 0, 7915, 5222, 5703, 1644, 1625, 0, 1625, 1625)
  , col2 = c(7907, 5703, 8004, 7521, 5222, 1625, 1625, 1644, 1625, 1505)
  , source = c('c', 'b', 'a', 'e', 'd', 'y', 'z', 'x', 'w', 'v'))

Hmmm .. Tôi gặp lỗi khi thực hiện lapply: Lỗi trong all_simple_paths (g, x [1L], x [2L]): Tại path.c: 77: Đỉnh bắt đầu không hợp lệ, Giá trị không hợp lệ
AlexP

Đầu ra cho chuỗi là gốc lá 1: 0 7907 2: 0 8004 3: 7915 7907 4: 7915 8004
AlexP

@AlexP, đỉnh của đồ thị phải là kiểu ký tự. Do đó, đó là lý do tại sao tôi sử dụng as.character trêncol*
chin gió12

À được rồi! Tôi đã bỏ lỡ việc thay đổi các cột thành một lớp nhân vật. Nó hoạt động! Cám ơn rất nhiều!
AlexP

1
@AlexP tôi đã thêm mã để xử lý id
chin gió12
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.