2016-07-18 1 views
2

私はRを初めて使用しているため、遭遇した特定の問題の回答を検索することができませんでした。私は列が列No1No2で一意の値を示すことになるデータフレームに新しい列を追加することができる追加することになりますどのように既存の列から(一意の値を抽出して)データフレームに列を追加する

d <- data.frame(Name = c("Jon", "Jon", "Jon", "Kel", "Kel", "Kel", "Don", "Don", "Don"), 
      No1 = c(1,2,3,1,1,1,3,3,3), 
      No2 = c(1,1,1,2,2,2,3,3,3)) 

Name No1 No2 
Jon 1 1 
Jon 2 1 
Jon 3 1 
Kel 1 2 
Kel 1 2 
Kel 1 2 
Don 3 3 
Don 3 3 
Don 3 3 
... 

は私のデータフレームは、以下のように見える場合もあろう( 1,2,3)、(1,2)、(3)ジョン、ケリー、ドン、それぞれについて

新しい列がID#命名されているのであれば、所望の結果が

d2 <- data.frame(Name = c("Jon", "Jon", "Jon", "Kel", "Kel", "Kel", "Don", "Don", "Don"), 
      No1 = c(1,2,3,1,1,1,3,3,3), 
      No2 = c(1,1,1,2,2,2,3,3,3), 
      ID1 = c(1,1,1,1,1,1,3,3,3), 
      ID2 = c(2,2,2,2,2,2,NA,NA,NA), 
      ID3 = c(3,3,3,NA,NA,NA,NA,NA,NA)) 

Name No1 No2 ID1 ID2 ID3 
Jon 1 1 1 2 3 
Jon 2 1 1 2 3 
Jon 3 1 1 2 3 
Kel 1 2 1 2 NA 
Kel 1 2 1 2 NA 
Kel 1 2 1 2 NA 
Don 3 3 3 NA NA 
Don 3 3 3 NA NA 
Don 3 3 3 NA NA 
なければなりません

答えて

3

tidyverseアプローチ:

# store distinct values in No1 and No2 
cols <- unique(unlist(d[,-1])) 
          # split No1 and No2 by Name, 
ids <- data.frame(t(sapply(split(d[,-1], d$Name), 
          # find unique values for each split, 
          function(x){y <- unique(unlist(x)) 
             # pad with NAs, 
             c(y, rep(NA, length(cols) - length(y))) 
          # and return a data.frame 
          }))) 
# fix column names 
names(ids) <- paste0('ID', cols) 
# turn rownames into column 
ids$Name <- rownames(ids) 
# join two data.frames on Name columns 
merge(d, ids, sort = FALSE) 

## Name No1 No2 ID1 ID2 ID3 
## 1 Jon 1 1 1 2 3 
## 2 Jon 2 1 1 2 3 
## 3 Jon 3 1 1 2 3 
## 4 Kel 1 2 1 2 NA 
## 5 Kel 1 2 1 2 NA 
## 6 Kel 1 2 1 2 NA 
## 7 Don 3 3 3 NA NA 
## 8 Don 3 3 3 NA NA 
## 9 Don 3 3 3 NA NA 

そして、ちょうどキックのために:ここで

library(dplyr) 
library(tidyr) 

     # evaluate separately for each name 
d %>% group_by(Name) %>% 
    # add a column of the unique values pasted together into a string 
    mutate(ID = paste(unique(c(No1, No2)), collapse = ' ')) %>% 
    # separate the string into individual columns, filling with NA and converting to numbers 
    separate(ID, into = paste0('ID', 1:3), fill = 'right', convert = TRUE) 

## Source: local data frame [9 x 6] 
## Groups: Name [3] 
## 
##  Name No1 No2 ID1 ID2 ID3 
## * <fctr> <dbl> <dbl> <int> <int> <int> 
## 1 Jon  1  1  1  2  3 
## 2 Jon  2  1  1  2  3 
## 3 Jon  3  1  1  2  3 
## 4 Kel  1  2  1  2 NA 
## 5 Kel  1  2  1  2 NA 
## 6 Kel  1  2  1  2 NA 
## 7 Don  3  3  3 NA NA 
## 8 Don  3  3  3 NA NA 
## 9 Don  3  3  3 NA NA 

は、基本的な分割適用-組み合わせるアプローチで素敵な基本バージョンです、ここにはを活用した創造的な代替ベースバージョンがあります分割/グループ化の代わりに:

# copy d so as not to distort original with factor columns 
d_f <- d 
# make No* columns factors to ensure similar table structure 
d_f[, -1] <- lapply(d[,-1], factor, levels = unique(unlist(d[, -1]))) 
# make tables of cols, sum to aggregate occurrences, and set as boolean mask for > 0 
tab <- Reduce(`+`, lapply(d_f[, -1], table, d_f$Name)) > 0 
# replace all TRUE values with values they tabulated 
tab <- tab * matrix(as.integer(rownames(tab)), nrow = nrow(tab), ncol = ncol(tab)) 
# replace 0s with NAs 
tab[tab == 0] <- NA 
# store column names 
cols <- paste0('ID', rownames(tab)) 
# sort each row, keeping NAs 
tab <- data.frame(t(apply(tab, 2, sort, na.last = T))) 
# apply stored column names 
names(tab) <- cols 
# turn rownames into column 
tab$Name <- rownames(tab) 
# join two data.frames on Name columns 
merge(d, tab, sort = FALSE) 

結果は同じです。

2

単一の外部パッケージ、すなわちdata.tableを使用して出力を得ることができます。 'data.frame'を 'Name'でグループ化した 'data.table'(setDT(d))に変換し、unlist.SDcolsに記載されている列に固有の値を取得し、dcastを 'long'から 'wide'元のデータセットonを「名前」列と結合します。

library(data.table) 
dcast(setDT(d)[, unique(unlist(.SD)) , Name, .SDcols = No1:No2], 
     Name~paste0("ID", rowid(Name)), value.var="V1")[d, on = "Name"] 
# Name ID1 ID2 ID3 No1 No2 
#1: Jon 1 2 3 1 1 
#2: Jon 1 2 3 2 1 
#3: Jon 1 2 3 3 1 
#4: Kel 1 2 NA 1 2 
#5: Kel 1 2 NA 1 2 
#6: Kel 1 2 NA 1 2 
#7: Don 3 NA NA 3 3 
#8: Don 3 NA NA 3 3 
#9: Don 3 NA NA 3 3 

あるいはこれが「名前」でグループ化された「No1の」と「NO2の」でunique要素をINGの第pasteずつラインで行うことができ、そして使用して3つの列に次にsplitそれをcSplitsplitstackshapeから。

library(splitstackshape) 
cSplit(setDT(d)[, ID:= paste(unique(c(No1, No2)), collapse=" ") , Name], "ID", " ") 
# Name No1 No2 ID_1 ID_2 ID_3 
#1: Jon 1 1 1 2 3 
#2: Jon 2 1 1 2 3 
#3: Jon 3 1 1 2 3 
#4: Kel 1 2 1 2 NA 
#5: Kel 1 2 1 2 NA 
#6: Kel 1 2 1 2 NA 
#7: Don 3 3 3 NA NA 
#8: Don 3 3 3 NA NA 
#9: Don 3 3 3 NA NA 

それともキック

d1 <- read.table(text=ave(unlist(d[-1]), rep(d$Name, 2), 
     FUN = function(x) paste(unique(x), collapse=" "))[1:nrow(d)], 
     header=FALSE, fill=TRUE, col.names= paste0("ID", 1:3)) 
cbind(d, d1) 
# Name No1 No2 ID1 ID2 ID3 
#1 Jon 1 1 1 2 3 
#2 Jon 2 1 1 2 3 
#3 Jon 3 1 1 2 3 
#4 Kel 1 2 1 2 NA 
#5 Kel 1 2 1 2 NA 
#6 Kel 1 2 1 2 NA 
#7 Don 3 3 3 NA NA 
#8 Don 3 3 3 NA NA 
#9 Don 3 3 3 NA NA 

NOTEためbaseVerseを使用して:使用なしパッケージと分裂に多くの努力なし。

3
library(dplyr) 
library(tidyr) 
d %>% 
    group_by(Name) %>% 
    mutate(unique_id = paste0(unique(c(No1, No2)), collapse = ",")) %>% 
    separate(., unique_id, paste0("id_", 1:max(c(.$No1, .$No2))), fill = "right") 
関連する問題