[英]Combine data frame rows in R based on multiple columns
我在R中有一个数据帧,每行有一个个体。 有时,个人出现在两行,我想根据重复的ID组合这些行。
问题是,每个人都有多个ID,当ID出现两次时, 它不一定出现在同一列中 。
这是一个示例数据框:
dat <- data.frame(a = c('cat', 'canine', 'feline', 'dog'),
b = c('feline', 'puppy', 'meower', 'wolf'),
c = c('kitten', 'barker', 'kitty', 'canine'),
d = c('shorthair', 'collie', '', ''),
e = c(1, 5, 3, 8))
> dat
a b c d e
1 cat feline kitten shorthair 1
2 canine puppy barker collie 5
3 feline meower kitty 3
4 dog wolf canine 8
这样行1和3应结合,因为ID b
行1的ID等于a
行3.同样的,ID a
排2的等于ID c
4行的,所以那些行应结合为好。
理想情况下,输出应该如下所示。
a.1 b.1 c.1 d.1 e.1 a.2 b.3 c.2 d.2 e.2
1 cat feline kitten shorthair 1 feline meower kitty 3
2 canine puppy barker collie 5 dog wolf canine 8
(请注意,根据作为空字符串的共享ID,未合并行。)
关于如何做到这一点的我的想法如下,但我很确定我已经走错了路,所以他们可能没有帮助解决问题。
我以为我可以为每一行分配行ID,然后融化数据。 在那之后,我可以逐行。 当我找到其中一个ID与前一行匹配的行时(例如,当第3行ID中的一个与第1行ID之一匹配时),我将更改当前行的行ID的每个实例以匹配先前的行ID (例如,所有行ID为3将更改为1)。
这是我一直在使用的代码:
dat$row.id <- 1:nrow(dat)
library(reshape2)
dat.melt <- melt(dat, id.vars = c('e', 'row.id'))
for (i in 2:nrow(dat.melt)) {
# This next step is just to ignore the empty values
if (grepl('^[[:space:]]*$', dat.melt$value[i])) {
next
}
earlier.instance <- dat.melt$row.id[which(dat.melt$value[1:(i-1)] == dat.melt$value[i])]
if (length(earlier.instance) > 0) {
earlier.row.id <- earlier.instance[1]
dat.melt$row.id[dat.melt$row.id == dat.melt$row.id[i]] <- earlier.row.id
}
}
这种方法存在两个问题。
row.id
和variable
,所以我不知道如何转换它以获得我上面显示的那种输出。 在这里使用dcast
将被迫使用聚合函数。 输出:
e row.id variable value
1 1 3 a cat
2 5 2 a canine
3 3 3 a feline
4 8 2 a dog
5 1 3 b feline
6 5 2 b puppy
7 3 3 b meower
8 8 2 b wolf
9 1 3 c kitten
10 5 2 c barker
11 3 3 c kitty
12 8 2 c canine
13 1 3 d shorthair
14 5 2 d collie
15 3 3 d
16 8 2 d
新答案。 有一些乐趣(/挫折)通过这个工作。 我敢肯定这不是最快的解决方案,但它应该让你过去我的其他答案。 让我解释:
dat <- data.table(a = c('cat', 'canine', 'feline', 'dog', 'cat','fido'),
b = c('feline', 'puppy', 'meower', 'wolf', 'kitten', 'dog'),
c = c('kit', 'barker', 'kitty', 'canine', 'feline','wolf'),
d = c('shorthair', 'collie', '', '','',''),
e = c(1, 2, 3, 4, 5, 6))
dat[, All := paste(a, b,c),]
两个更改: dat$e
现在是一个索引列,因此它只是它所在行的数字位置。 如果e
非常重要,您可以创建一个新列来替换它。
下面是第一个循环。 这使得3分新列FirstMatchingID
等,这些都是像以前一样:他们给出的最早(最低行号)的折射率匹配dat$All
的a
b
和c
。
for(i in 2:nrow(dat)) {
x <- grepl(dat[i]$a, dat[i-(1:i)]$All)
y <- max(which(x %in% TRUE))
dat[i, FirstMatchingID := dat[i-y]$e]
x2 <- grepl(dat[i]$b, dat[i-(1:i)]$All)
y2 <- max(which(x2 %in% TRUE))
dat[i, SecondMatchingID := dat[i-y2]$e]
x3 <- grepl(dat[i]$c, dat[i-(1:i)]$All)
y3 <- max(which(x3 %in% TRUE))
dat[i, ThirdMatchingID := dat[i-y3]$e]
}
接下来,我们使用pmin
查找MatchingID
列的最早匹配行,并将其设置在自己的列中。 这是如果你有一个匹配a
行25和匹配b
行12; 它会给你12(我认为这是你想要的根据你的问题)。
dat$MinID <- pmin(dat$FirstMatchingID, dat$SecondMatchingID, dat$ThirdMatchingID, na.rm=T)
最后,这个循环将完成3件事,创建一个FinalID
列,其中包含来自e
所有匹配的ID号:
MinID
为NA
(无匹配),将FinalID
设置为e
MinID
是一个数字,找到该行(最早的匹配)并检查其 MinID
是否为数字; 如果不是,则没有先前的匹配,并将FinalID
设置为MinID
i
最早匹配的行本身具有较早的匹配。 这将找到匹配并将其设置为FinalID
。 for (i in 1:nrow(dat)) { x <- dat[i]$MinID if (is.na(dat[i]$MinID)) { dat[i, FinalID := e] } else if (is.na(dat[x]$MinID)) { dat[i, FinalID := MinID] } else dat[i, FinalID := dat[x]$MinID] }
我认为应该这样做; 让我知道事情的后续。 我没有声称它的效率或速度。
这是一次业余尝试。 我认为它可以满足您的需求。 我已经将data.frame(现在是data.table)扩展了两行,以提供更好的示例。
此循环创建一个新列dat$FirstMatchingID
,其中包含来自最早匹配的dat$e
的ID。 我只是为了匹配第一列, dat$a
,但我认为它可以很容易地扩展到b
和c
。
library(data.table)
dat <- data.table(a = c('cat', 'canine', 'feline', 'dog', 'feline','puppy'),
b = c('feline', 'puppy', 'meower', 'wolf', 'kitten', 'dog'),
c = c('kitten', 'barker', 'kitty', 'canine', 'cat','wolf'),
d = c('shorthair', 'collie', '', '','',''),
e = c(1, 5, 3, 8, 4, 6))
dat[, All := paste(a, b,c),]
for(i in 2:nrow(dat)) {
print(dat[i])
x <- grepl(dat[i]$a, dat[i-(1:i)]$All)
y <- max(which(x %in% TRUE))
dat[i, FirstMatchingID := dat[i-y]$e]
}
结果:
a b c d e All FirstMatchingID
1: cat feline kitten shorthair 1 cat feline kitten NA
2: canine puppy barker collie 5 canine puppy barker NA
3: feline meower kitty 3 feline meower kitty 1
4: dog wolf canine 8 dog wolf canine NA
5: feline kitten cat 4 feline kitten cat 1
6: puppy dog wolf 6 puppy dog wolf 5
然后,您必须找出如何组合行以获得所需结果,但希望这会有所帮助!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.