R 创建重复id/键的映射表

R 创建重复id/键的映射表,r,dataframe,duplicates,data.table,dplyr,R,Dataframe,Duplicates,Data.table,Dplyr,我有一个统计例程,它不喜欢行完全重复(没有ID)导致空距离 因此,我首先检测我删除的重复项,应用我的例程并合并保留的记录 为简单起见,请考虑使用行名< /代码>为ID/KEY。 我找到了以下方法来实现我在base R中的成绩: data <- data.frame(x=c(1,1,1,2,2,3),y=c(1,1,1,4,4,3)) # check duplicates and get their ID -- cf. https://stackoverflow.com/questions

我有一个统计例程,它不喜欢行完全重复(没有ID)导致空距离

因此,我首先检测我删除的重复项,应用我的例程并合并保留的记录

为简单起见,请考虑使用<代码>行名< /代码>为ID/KEY。

我找到了以下方法来实现我在base R中的成绩:

data <- data.frame(x=c(1,1,1,2,2,3),y=c(1,1,1,4,4,3))

# check duplicates and get their ID -- cf. https://stackoverflow.com/questions/12495345/find-indices-of-duplicated-rows
dup1 <- duplicated(data)
dupID <- rownames(data)[dup1 | duplicated(data[nrow(data):1, ])[nrow(data):1]]

# keep only those records that do have duplicates to preveng running folowing steps on all rows
datadup <- data[dupID,]

# "hash" row
rowhash <- apply(datadup, 1, paste, collapse="_")

idmaps <- split(rownames(datadup),rowhash)
idmaptable <- do.call("rbind",lapply(idmaps,function(vec)data.frame(mappedid=vec[1],otherids=vec[-1],stringsAsFactors = FALSE)))

data使用
tidyverse
的解决方案。我通常不在行名称中存储信息,因此我创建了
ID
ID2
来存储信息。当然,你可以根据自己的需要改变

library(tidyverse)

idmaptable <- data %>%
  rowid_to_column() %>%
  group_by(x, y) %>%
  filter(n() > 1) %>%
  unite(ID, x, y) %>%
  mutate(ID2 = 1:n()) %>%
  group_by(ID) %>%
  mutate(ID_type = ifelse(row_number() == 1, "mappedid", "otherids")) %>%
  spread(ID_type, rowid) %>%
  fill(mappedid) %>%
  drop_na(otherids) %>%
  mutate(ID2 = 1:n())

idmaptable
# A tibble: 3 x 4
# Groups:   ID [2]
     ID   ID2 mappedid otherids
  <chr> <int>    <int>    <int>
1   1_1     1        1        2
2   1_1     2        1        3
3   2_4     1        4        5
库(tidyverse)
idmaptable%
rowid_到_列()%>%
(x,y)%>%
过滤器(n()>1)%>%
联合(ID,x,y)%>%
突变(ID2=1:n())%>%
分组依据(ID)%>%
mutate(ID_type=ifelse(row_number()=1,“mappedid”,“otherid”))%>%
排列(ID\U类型,rowid)%>%
填充(mappedid)%>%
下拉菜单(其他ID)%>%
突变(ID2=1:n())
idmaptable
#一个tibble:3x4
#组别:ID[2]
ID ID2映射到其他ID
1   1_1     1        1        2
2   1_1     2        1        3
3   2_4     1        4        5

使用
tidyverse
的解决方案。我通常不在行名称中存储信息,因此我创建了
ID
ID2
来存储信息。当然,你可以根据自己的需要改变

library(tidyverse)

idmaptable <- data %>%
  rowid_to_column() %>%
  group_by(x, y) %>%
  filter(n() > 1) %>%
  unite(ID, x, y) %>%
  mutate(ID2 = 1:n()) %>%
  group_by(ID) %>%
  mutate(ID_type = ifelse(row_number() == 1, "mappedid", "otherids")) %>%
  spread(ID_type, rowid) %>%
  fill(mappedid) %>%
  drop_na(otherids) %>%
  mutate(ID2 = 1:n())

idmaptable
# A tibble: 3 x 4
# Groups:   ID [2]
     ID   ID2 mappedid otherids
  <chr> <int>    <int>    <int>
1   1_1     1        1        2
2   1_1     2        1        3
3   2_4     1        4        5
库(tidyverse)
idmaptable%
rowid_到_列()%>%
(x,y)%>%
过滤器(n()>1)%>%
联合(ID,x,y)%>%
突变(ID2=1:n())%>%
分组依据(ID)%>%
mutate(ID_type=ifelse(row_number()=1,“mappedid”,“otherid”))%>%
排列(ID\U类型,rowid)%>%
填充(mappedid)%>%
下拉菜单(其他ID)%>%
突变(ID2=1:n())
idmaptable
#一个tibble:3x4
#组别:ID[2]
ID ID2映射到其他ID
1   1_1     1        1        2
2   1_1     2        1        3
3   2_4     1        4        5
带有数据。表格

library(data.table)
setDT(data)

# tag groups of dupes
data[, g := .GRP, by=x:y]

# do whatever analysis
f = function(DT) Reduce(`+`, DT)
resDT = unique(data, by="g")[, res := f(.SD), .SDcols = x:y][]

# "update join" the results back to the main table if needed
data[resDT, on=.(g), res := i.res ]
OP跳过了示例的一个中心部分(重复数据的使用),所以我只是用数据编写了
f

library(data.table)
setDT(data)

# tag groups of dupes
data[, g := .GRP, by=x:y]

# do whatever analysis
f = function(DT) Reduce(`+`, DT)
resDT = unique(data, by="g")[, res := f(.SD), .SDcols = x:y][]

# "update join" the results back to the main table if needed
data[resDT, on=.(g), res := i.res ]

OP跳过了示例的一个中心部分(重复数据的使用),因此我对基本R解决方案做了一些改进

df <- data[duplicated(data)|duplicated(data, fromLast = TRUE),]

do.call(rbind, lapply(split(rownames(df), 
               do.call(paste, c(df, sep = '_'))), function(i) 
                                                  data.frame(mapped = i[1], 
                                                             others = i[-1], 
                                                             stringsAsFactors = FALSE)))
当然


对基本R解决方案的一些改进

df <- data[duplicated(data)|duplicated(data, fromLast = TRUE),]

do.call(rbind, lapply(split(rownames(df), 
               do.call(paste, c(df, sep = '_'))), function(i) 
                                                  data.frame(mapped = i[1], 
                                                             others = i[-1], 
                                                             stringsAsFactors = FALSE)))
当然


谢谢很好的锻炼!我将验证data.table选项,因为我最终打算使用此软件包。请注意,操作非常复杂,从这个意义上讲,有许多步骤,逻辑不那么容易阅读/分解/理解!谢谢你的评论。技巧与否取决于用户的感受。在我的解决方案中,每一步都是一个函数,只做一件事。如果你知道每个函数代表什么,你可以“大声读出来”。对我来说,有时候这些简洁的方法太“紧凑”了。谢谢。很好的锻炼!我将验证data.table选项,因为我最终打算使用此软件包。请注意,操作非常复杂,从这个意义上讲,有许多步骤,逻辑不那么容易阅读/分解/理解!谢谢你的评论。技巧与否取决于用户的感受。在我的解决方案中,每一步都是一个函数,只做一件事。如果你知道每个函数代表什么,你可以“大声读出来”。对我来说,有时候这些简洁的方法太“紧凑”了。谢谢!令人印象深刻的是它是多么简洁。我按照我的意愿验证了这一点,重写了部分代码以使用
data.table
。如果我想用另一种方式指定“by”列,该怎么办?我将有一个全局ID列(设置为键),我必须首先将其从进程中删除——因为我的复制映射进程显然必须在没有此ID列的情况下工作。@Eric Sure。您可以执行
cols=setdiff(名称(数据),“ID”)
,然后像
by=cols
那样传递cols。SDcols=cols
。传递这些参数的各种选项包含在
?data.table
中。有很多。我的笔记中还有一个“指定列”的列表,谢谢!令人印象深刻的是它是多么简洁。我按照我的意愿验证了这一点,重写了部分代码以使用
data.table
。如果我想用另一种方式指定“by”列,该怎么办?我将有一个全局ID列(设置为键),我必须首先将其从进程中删除——因为我的复制映射进程显然必须在没有此ID列的情况下工作。@Eric Sure。您可以执行
cols=setdiff(名称(数据),“ID”)
,然后像
by=cols
那样传递cols。SDcols=cols
。传递这些参数的各种选项包含在
?data.table
中。有很多。在我的笔记中,在“指定列”下面有一个列表,的确更短,更短。