我不确定如何在搜索时正确说出这一点,很抱歉,如果这有一个简单的答案。
我有58个数据帧,每个约25,000行,我从.csv获得。他们看起来像这样:
Probe.Id Gene.Id Score.d
1418126_at 6352 28.52578
145119_a_at 2192 24.87866
1423477_at NA 24.43532
1434193_at 100506144///9204 6.22395
理想情况下,我想在“///”处拆分ID并将它们放在新行上。像这样:
Probe.Id Gene.Id Score.d
1418126_at 6352 28.52578
145119_a_at 2192 24.87866
1423477_at NA 24.43532
1434193_at 100506144 6.22395
1434193_at 9204 6.22395
使用strsplit允许我将Gene.Id作为一个字符向量列表,但是一旦我有了这个,我不确定最有效的方法是使用正确的值获取每个单独的id在他们自己的行上来自其他专栏。理想情况下,我不想只循环25,000行。
如果有人知道正确的方法,我会非常感激。
编辑:我应该补充说,有一个复杂的因素是有些行有这样的ID:
333932///126961///653604///8350///8354///8355///8356///8968///8352///8358///8351///8353///8357"
我不知道连续的最大数量是多少。
答案 0 :(得分:6)
编辑: OP评论后的新解决方案。使用data.table
非常简单:
df <- structure(list(Probe.Id = c("1418126_at", "145119_a_at", "1423477_at",
"1434193_at", "100_at"), Gene.Id = c("6352", "2192", NA,
"100506144///9204", "100506144///100506146///100506148///100506150"),
Score.d = c(28.52578, 24.87866, 24.43532, 6.22395, 6.22395)),
.Names = c("Probe.Id", "Gene.Id", "Score.d"), row.names = c(NA, 5L),
class = "data.frame")
require(data.table)
dt <- data.table(df)
dt.out <- dt[, list(Probe.Id = Probe.Id,
Gene.Id = unlist(strsplit(Gene.Id, "///")),
Score.d = Score.d), by=1:nrow(dt)]
> dt.out
# nrow Probe.Id Gene.Id Score.d
# 1: 1 1418126_at 6352 28.52578
# 2: 2 145119_a_at 2192 24.87866
# 3: 3 1423477_at NA 24.43532
# 4: 4 1434193_at 100506144 6.22395
# 5: 4 1434193_at 9204 6.22395
# 6: 5 100_at 100506144 6.22395
# 7: 5 100_at 100506146 6.22395
# 8: 5 100_at 100506148 6.22395
# 9: 5 100_at 100506150 6.22395
如果fixed = TRUE
是固定模式,您可以将strsplit
添加到///
表达式以进一步加快速度。
替代再次使用data.table
。考虑到strsplit
是一个向量化操作,并且在整个Gene.Id
列上运行它会比在每次运行1行时快得多(即使data.table
运行很快,你可以通过将前面的代码分成两个步骤来获得更多的加速:
# first split using strsplit (data.table can hold list in its columns!!)
dt[, Gene.Id_split := strsplit(dt$Gene.Id, "///", fixed=TRUE)]
# then just unlist them
dt.2 <- dt[, list(Probe.Id = Probe.Id,
Gene.Id = unlist(Gene.Id_split),
Score.d = Score.d), by = 1:nrow(dt)]
我刚刚复制了此示例中显示的data.table
多次,直到我获得了295245
行。然后我使用rbenchmark
:
# first function
DT1 <- function() {
dt.1 <- dt[, list(Probe.Id = Probe.Id,
Gene.Id = unlist(strsplit(Gene.Id, "///", fixed = TRUE)),
Score.d = Score.d), by=1:nrow(dt)]
}
# expected to be faster function
DT2 <- function() {
dt[, Gene.Id_split := strsplit(dt$Gene.Id, "///", fixed=TRUE)]
# then just unlist them
dt.2 <- dt[, list(Probe.Id = Probe.Id, Gene.Id = unlist(Gene.Id_split), Score.d = Score.d), by = 1:nrow(dt)]
}
require(rbenchmark)
benchmark(DT1(), DT2(), replications=10, order="elapsed")
# test replications elapsed relative user.self sys.self
# 2 DT2() 10 15.708 1.000 14.390 0.391
# 1 DT1() 10 24.957 1.589 23.723 0.436
对于此示例,您的速度提高了1.6倍。但这取决于///
的条目数。希望这会有所帮助。
OLD解决方案:(用于连续性)
一种方法是:1)发生此find the positions
的{{1}},2)///
,3)extract
,4)duplicate
和5) sub
他们。
combine
答案 1 :(得分:2)
这是使用strsplit
和merge
dat <- read.table(text ='Probe.Id Gene.Id Score.d
1418126_at 6352 28.52578
145119_a_at 2192 24.87866
1423477_at NA 24.43532
1434193_at 100506144///9204 6.22395',header=T,stringsAsFactors=F)
dat1 <- dat
xx <- do.call(rbind,strsplit(dat$Gene.Id,split='///'))
dat[which(xx[,1]!=xx[,2]),2] <- xx[which(xx[,1]!=xx[,2]),1]
dat1[which(xx[,1]!=xx[,2]),2] <- xx[which(xx[,1]!=xx[,2]),2]
merge(dat,dat1,all.y=T,all.x=T)
Probe.Id Gene.Id Score.d
1 1418126_at 6352 28.52578
2 1423477_at <NA> 24.43532
3 1434193_at 100506144 6.22395
4 1434193_at 9204 6.22395
5 145119_a_at 2192 24.87866
答案 2 :(得分:2)
这是一个使用data.frame
构造函数的方法,使用它默认循环输入向量的“特性”:
do.call(rbind,
apply(dat, 1, function(x)
data.frame(Probe.ID=x['Probe.Id'],
Gene.Id=strsplit(x['Gene.Id'], '///'),
Score.d=x['Score.d'],
row.names=NULL
)
)
)
## Probe.ID Gene.Id Score.d
## 1 1418126_at 6352 28.52578
## 2 145119_a_at 2192 24.87866
## 3 1423477_at <NA> 24.43532
## 4 1434193_at 100506144 6.22395
## 5 1434193_at 9204 6.22395