2016-09-28 10 views
1

私のdfdf(つまり重複がある場合)の一致があるかどうかを指定するlink列(型リスト)を持ちます。一致の列に基づいてdfの重複した行を削除する

df <- data.frame(id=1:7,link=I(list(c(2,3),c(1,3),c(1,2),NA,NA,7,6))) 

    id link 
1 1 2, 3 
2 2 1, 3 
3 3 1, 2 
4 4 NA 
5 5 NA 
6 6 7 
7 7 6 

Iは、リンクされたレコードをそれらの行のためにのみ最初に一致した行(すなわち、IDによって注文に対して)を維持するdfをサブセットたいです。私がしたい:

id link 
1 1 2, 3 
2 4 NA 
3 5 NA 
4 6 7 

私はto_removedfから削除する行のid値を格納するためにループを試してみました。それは現時点ではうまくいきません。私はこれを思っています。

to_remove <- character(0) 
for (n in 1:nrow(df)) { 
    links <- df$link[[n]] 
    if (all(is.na(links))) next # skip if no links available 
    add <- ifelse(links %in% to_remove, NA,links) 
    add <- add[!is.na(add)] 
    if (length(add > 0)) to_remove <- c(to_remove,add) 
} 

これを簡単な方法で行い、ループを回避することはできますか?

+2

最終行が含まれていないのはなぜですか(7 6)。 – akrun

+0

'id == 6 'の行の' link'の値は '7'です。これは、 '6'と' 7'が実際に同じレコードであることを示しています。一致したレコードの最初の出現のみを保持したいとします(つまり、 'id == 6のみを保持し、' id == 7'を破棄します) 。 –

答えて

5

library(data.table) 
DT <- data.table(id = rep(df$id, lengths(df$link)), link = unlist(df$link)) 
DT[DT[, .I[!any(id > link) | is.na(link)], by = id]$V1][, .(link = toString(link)), by = id] 

ができます:

id link 
1: 1 2, 3 
2: 4 NA 
3: 5 NA 
4: 6 7 

説明

  • まず、リストをunlistingすることにより、新しいdata.frame/data.tableを作成しますの細胞でを開き、新しいdata.frame/data.tableを作成します。
  • 次に、含める条件が満たされているインデックスを作成し、このサブセットを選択します。
  • 最後に、リンク列の値を各IDのリストに戻します。

またはdplyr/tidyr組み合わせ使用:

library(dplyr) 
library(tidyr) 
df %>% 
    unnest(link) %>% 
    group_by(id) %>% 
    filter(!any(id > link) | is.na(link)) %>% 
    summarise(link = toString(link)) 

同様の結果が得られる:

# A tibble: 4 × 2 
    id link 
    <int> <chr> 
1  1 2, 3 
2  4 NA 
3  5 NA 
4  6  7 

または基地R使用:

最初に一致した行

によってあなたはidでご注文に関して意味

dfn <- data.frame(id = rep(df$id, lengths(df$link)), link = unlist(df$link)) 
dfn <- dfn[!dfn$id %in% unique(dfn$id[which(dfn$id > dfn$link)]),] 
aggregate(link ~ id, dfn, toString, na.action = na.pass) 
+1

これはすばらしいことですが、 'data.table'ソリューションの説明が多く役に立ちました。 –

1

xの削除は、すべての行についてlinkの値に依存します。1:x-1ベクトル化は困難です。すべての行を1回ループし、冗長行の(ブール)インデックスを保存することをお勧めします。あなたはあなたの実装がちょっとばかげていると思っていました。使用

df <- data.frame(id=1:7,link=I(list(c(2,3),c(1,3),c(1,2),NA,NA,7,6))) 

keep <- rep(TRUE, nrow(df)) 
for (i in 1:nrow(df)) { 
    idx <- df$link[[i]] 
    idx_larger_than_me <- idx[idx > i] 
    print(idx_larger_than_me) 
    keep[idx_larger_than_me] <- FALSE 
} 
df2 <- df[keep,] 
+0

ピーターさん、ありがとうございました、まさに私がやろうとしていたことです。これは機能的な回答ではあるが、私はループを避けることができることを期待していたので、私はそれを受け入れなかった。 –

1

場合は、次の作業をする必要があります:

library(dplyr) 
library(tidyr) 
result <- df %>% unnest(link) %>% 
       filter(is.na(link) | link > id & !duplicated(link)) %>% 
       group_by(id) %>% 
       nest(link, .key=link) 
print(result) 
### A tibble: 4 x 3 
##  id    link 
## <int>   <list> 
##1  1 <tibble [2 x 1]> 
##2  4 <tibble [1 x 1]> 
##3  5 <tibble [1 x 1]> 
##4  6 <tibble [1 x 1]> 
print(result$link) 
##[[1]] 
### A tibble: 2 x 1 
## link 
## <dbl> 
##1  2 
##2  3 
## 
##[[2]] 
### A tibble: 1 x 1 
## link 
## <dbl> 
##1 NA 
## 
##[[3]] 
### A tibble: 1 x 1 
## link 
## <dbl> 
##1 NA 
## 
##[[4]] 
### A tibble: 1 x 1 
## link 
## <dbl> 
##1  7 

ノート:

  1. まずunnest
  2. (同じ id用) link sは別の行にあるよう is.na(link)
  3. link > idlinkidよりも大きいの行を維持するいかなるリンクを持たないすべての行を保ちます。これは、リンクされた行がIDよりも大きいので、一致の順序がidである場合、最初の一致を維持します。
  4. !duplicated(link)はリンク内の重複を削除します。
  5. 次に、nest
関連する問題