I would like to transform/modify the content of dataframe. Basically I have a dataframe like below:
bins pval
1 2L:1:150 0.9224217
2 2L:151:300 0.9478824
3 2L:301:450 0.9671139
4 2L:451:600 0.9280847
5 2L:601:750 0.9698584
6 2L:751:900 0.9725379
And I would like to transform/modify into another dataframe like this, where I split the content of my "bins" column (first row) into 150 rows containing the same values. And so on for the second row.
chr开发者_Python百科 pos pval
1 2L 1 0.9224217
2 2L 2 0.9224217
3 2L 3 0.9224217
4 2L 4 0.9224217
5 2L 5 0.9224217
...
150 2L 150 0.9224217
151 2L 151 0.9478824
152 2L 152 0.9478824
153 2L 153 0.9478824
etc...
Any help much appreciated,
Ben
The quick answer which may be, I fear, too specific and may need generalization. Assume the first dataframe is named "df1":
data.frame(chr="2L", pos=1:(150*NROW(df1)), pval=rep(df1$pval, each=150) )
Argument recycling should make the "chr" long enough without a rep function.
Edit in reply to comment. If the repeat length is always 150 then the fix is easy:
data.frame(chr = rep(substr(df1$bins, 1,2), each=150),
pos = 1:(150*NROW(df1)),
pval = rep(df1$pval, each=150) )
Here's an attempt at a more generalized answer that could be made more efficient. I couldn't find an easy way to convert from a factor
to numeric
while retaining the levels in the new numeric
column. Regardless, this should work and can support different values for the "chr" column and different numbers of rows:
library(plyr)
df <- read.table(textConnection(" bins pval
1 2L:1:150 0.9224217
2 2L:151:300 0.9478824
3 2L:301:450 0.9671139
4 2L:451:600 0.9280847
5 2L:601:750 0.9698584
6 2L:751:900 0.9725379
"), header = TRUE)
#Split bins
df.split <- data.frame(matrix(unlist(strsplit(as.character(df$bins), ":")), ncol = 3, byrow = TRUE ))
colnames(df.split) <- c("chr", "low", "high")
df.split$low <- as.numeric(as.character(df.split$low))
df.split$high <- as.numeric(as.character(df.split$high))
#Attach the pval from original df
df.split$pval <- df[, 2]
df.new <- adply(df.split, 1, summarise, pos = (low - 1) + seq(low:high))
df.new <- df.new[, c(1, 5, 4)]
Firs import with stringsAsFactors = FALSE in order not to get factors (or use Chase answer to convert to character):
df <- read.table(textConnection(" bins pval
1 2L:1:150 0.9224217
2 2L:151:300 0.9478824
3 2L:301:450 0.9671139
4 2L:451:600 0.9280847
5 2L:601:750 0.9698584
6 2L:751:900 0.9725379
"), header = TRUE, stringsAsFactors = FALSE)
Now, the rest:
split <- strsplit(df$bins, ":")
df$chr <- sapply(split, "[[", 1)
reps <- sapply(split, function(el) diff(as.numeric(el[2:3]))+1)
df[rep(1:nrow(df), reps), c("chr", "pval")]
chr pval
1 2L 0.9224217
1.1 2L 0.9224217
1.2 2L 0.9224217
1.3 2L 0.9224217
1.4 2L 0.9224217
1.5 2L 0.9224217
1.6 2L 0.9224217
1.7 2L 0.9224217
1.8 2L 0.9224217
1.9 2L 0.9224217
1.10 2L 0.9224217
...
精彩评论