Matching and pasting with data frames in R - regex

I'm having trouble with a match and paste problem. I have a data frame like
df
# X1 X2 X3 X4 X5 X6
#t1 <NA> <NA> AU 78 <NA> <NA>
#t2 dA AK <NA> <NA> 5 <NA>
#t3 ip <NA> <NA> <NA> <NA> <NA>
#t4 <NA> <NA> <NA> <NA> <NA> BA
I want it to look like this after operations,
newdf
# X1 X2 X3 X4 X5 X6
#v1 <NA> <NA> <NA> <NA> <NA> <NA>
#v2 AU78 <NA> <NA> <NA> <NA> <NA>
#v3 AK5 <NA> <NA> <NA> <NA> <NA>
#v4 <NA> <NA> <NA> <NA> <NA> BA
The process should first search for values that start with 'A'. df[1,3], df[2,2] in this case. Then paste that value to any other numbers further to the right of it (there will always be one number to the right of it). Also, to help, there will never be stray characters in between a target element (like 'AK') and the number to the right of it; only NAs will seperate them.
Those combined new values need to be brought to the first column, and one row down from where it was. It does not matter if values existing in the first row are overwritten.
My pattern locator is,
pat.locate <- lapply(df, function(x) grep('^A', x))
un.pat <- unlist(pat.locate)
#X2 X3
# 2 1
This looked like a good start. From there,
df[un.pat, names(un.pat)]
# X2 X3
#t2 AK <NA>
#t1 <NA> AU
So the target values are found with their column and row indexes. But I need the values to the right of those indexes. To subset the entire rows,
full.row <- df[un.pat, ]
# X1 X2 X3 X4 X5 X6
#t2 dA AK <NA> <NA> 5 <NA>
#t1 <NA> <NA> AU 78 <NA> <NA>
I paste the non-NA values, but you can tell what's going to happen,
paste(full.row[!is.na(full.row)], collapse='')
#[1] "dAAKAU785"
To divide it up, an apply over the rows was used:
pasty <- function(x) paste(x[!is.na(x)], collapse='')
pasted.rows <- apply(full.row, 1, pasty)
# t2 t1
#"dAAK5" "AU78"
That still leaves the stray string at the beginning. If I found a good regex to tell it to cast that off I'd have,
good.regex
# t2 t1
# "AK5" "AU78"
I could then subset the whole data frame based on those indices with,
df[names(good.regex), 1] <- good.regex
df
# X1 X2 X3 X4 X5 X6
#t1 AU78 <NA> AU 78 <NA> <NA>
#t2 AK5 AK <NA> <NA> 5 <NA>
#t3 ip <NA> <NA> <NA> <NA> <NA>
#t4 <NA> <NA> <NA> <NA> <NA> BA
But I'm still left with having to move the pasted values down by one.
df[names(good.regex)+1, 1] <- good.regex
#Error in names(good.regex) + 1 : non-numeric argument to binary operator
We obviously can't add a numeric to a named-style subset. I feel like I'm missing some element early on that's leading me down a difficult path to a solution. A regex would have to be a sub out that uses the pattern match and a look-behind that I can't crack. I think I'm working myself into a corner that is unnecessary. Any help is appreciated.
Data
df <- structure(list(X1 = c(NA, "dA", "ip", NA), X2 = c(NA, "AK", NA,
NA), X3 = c("AU", NA, NA, NA), X4 = c("78", NA, NA, NA), X5 = c(NA,
"5", NA, NA), X6 = c(NA, NA, NA, "BA")), .Names = c("X1", "X2",
"X3", "X4", "X5", "X6"), row.names = c("t1", "t2", "t3", "t4"
), class = "data.frame")
newdf <- structure(list(X1 = structure(c(NA, 2L, 1L, NA), .Names = c("v1",
"v2", "v3", "v4"), .Label = c("AK5", "AU78"), class = "factor"),
X2 = structure(c(NA_integer_, NA_integer_, NA_integer_, NA_integer_
), .Names = c("v1", "v2", "v3", "v4"), .Label = character(0), class = "factor"),
X3 = structure(c(NA_integer_, NA_integer_, NA_integer_, NA_integer_
), .Names = c("v1", "v2", "v3", "v4"), .Label = character(0), class = "factor"),
X4 = structure(c(NA_integer_, NA_integer_, NA_integer_, NA_integer_
), .Names = c("v1", "v2", "v3", "v4"), .Label = character(0), class = "factor"),
X5 = structure(c(NA_integer_, NA_integer_, NA_integer_, NA_integer_
), .Names = c("v1", "v2", "v3", "v4"), .Label = character(0), class = "factor"),
X6 = structure(c(NA, NA, NA, 1L), .Names = c("v1", "v2",
"v3", "v4"), .Label = "BA", class = "factor")), .Names = c("X1",
"X2", "X3", "X4", "X5", "X6"), row.names = c("v1", "v2", "v3",
"v4"), class = "data.frame")

For what I understand according to your output example, the point is to collapse a A* character and its following number in the same row, then move this new entity down to the first column one row below. While "erasing" the original line (row 1 of newdf filled with NA) but keeping lines with no-match intact if they're not affected by the previous movement (row 4).
Your main problem was to collapse on the full row, instead of collapsing only its end.
## original data
df <- structure(list(X1 = c(NA, "dA", "ip", NA),
X2 = c(NA, "AK", NA, NA),
X3 = c("AU", NA, NA, NA),
X4 = c("78", NA, NA, NA),
X5 = c(NA, "5", NA, NA),
X6 = c(NA, NA, NA, "BA")),
.Names = c("X1", "X2", "X3", "X4", "X5", "X6"),
row.names = c("t1", "t2", "t3", "t4"), class = "data.frame")
df
X1 X2 X3 X4 X5 X6
t1 <NA> <NA> AU 78 <NA> <NA>
t2 dA AK <NA> <NA> 5 <NA>
t3 ip <NA> <NA> <NA> <NA> <NA>
t4 <NA> <NA> <NA> <NA> <NA> BA
This following function grab the rows with the matching pattern but collapse only from this pattern to the end of the row, while forgetting its beginning. Thus avoiding the problem encountered with non matching stray character (the dA of your example) :
locateAndPaste <- function(x){
if(TRUE %in% grepl('^A', df[x,])){
endRow <- df[x, grep('^A', df[x,]):length(df)]
pasted.rows <- paste(endRow[!is.na(endRow)], collapse='')
}
else{NA}
}
The else element prevents throwing out errors if no match is found.
newEntity <- sapply(1:nrow(df), locateAndPaste)
# [1] "AU78" "AK5" NA NA
Two matching pattern have been found in row 1 and 2 and none in row 3 and 4.
As you can see the collapsing part worked perfectly.
Your second problem was to move one row down, and the impossibility of adding number to a character string. As I'm not subsetting on the names but on the indexes, the problem is easily avoided:
(in order to be complete, I've added a line at the end of this post regarding the conversion to numeric of those names)
## the newEntity element is already ordered according to the original row numbers
originalRowNumbers <- grep("^A", newEntity)
# [1] 1 2
From then, it's pretty straight forward :
newdf <- df ## all operations can be done on the original df,
## this copy is made only for the sake of the example.
## as per your example, "erase" the original lines where a matching pattern was found
## that will also prevent orphan lines if a no match have been found in the above line
newdf[originalRowNumbers, ] <- rep(NA, length(df))
## place the new entity in the first column one row below
newdf[originalRowNumbers+1, 1] <- newEntity[originalRowNumbers]
## fill the rest of this row with NA as per your example
newdf[originalRowNumbers+1, 2:length(df)] <- NA
newdf
X1 X2 X3 X4 X5 X6
t1 <NA> <NA> <NA> <NA> <NA> <NA>
t2 AU78 <NA> <NA> <NA> <NA> <NA>
t3 AK5 <NA> <NA> <NA> <NA> <NA>
t4 <NA> <NA> <NA> <NA> <NA> BA
However, if a matching pattern were to be found in the last row, an extra row will be added to newdf. In order to avoid that, it's possible to shorten the initial selection :
newEntity <- sapply(1:(nrow(df)-1), locateAndPaste)
To be complete : in your example it's possible to grab only the number in the names of good.regex and then feed them to your subset :
idx.goood.regex <- as.numeric(gsub("t","", names(good.regex)))
# [1] 2 1
df[idx.good.regex+1, 1] <- good.regex
Note that only works because good.regex is of class character. An error would occur if good.regex was a data.frame.

Related

conditional replacement between two data.frames by colnames and variables in R

I am trying to replace the values of a dataframe by the values of a variable from another dataframe based on matching colnames from the first one. I was digging around and found some lines of code but the output is not the expected
data<-data.frame(ASV10=c(0,0,1,0,0),ASV78=c(1,0,0,0,0),ASV34=c(0,0,0,0,1))
data2<-data.frame(var=c("ASV78","ASV10","ASV34"),trat=c("A","B","C"),stringsAsFactors = FALSE)
I would like to change numerical values of data in that way: if 0 change to NA if is higher than 0 to the corresponding value of trat in data2
First I changed all 0 values in data to NA
data[data == 0] <- NA
Then I sorted data by its names and data2 by var (it has same values than names(data))
data<-data[,sort(names(data))]
data2 <- data2[order(data2$var),]
Then I tried to change values of data that are not NA by values of data2$trat
data[match(colnames(data),data2$var)]<-ifelse(is.na(data),NA,data2$trat)
However I get
ASV10 ASV34 ASV78
1 <NA> <NA> C
2 <NA> <NA> <NA>
3 A <NA> <NA>
4 <NA> <NA> <NA>
5 <NA> B <NA>
It works partially. Respects NA places,replacing non 0 values, but values of data2$trat do not
correspond between colnames(data) and data2$var
ASV10 ASV34 ASV78
1 <NA> <NA> A
2 <NA> <NA> <NA>
3 B <NA> <NA>
4 <NA> <NA> <NA>
5 <NA> C <NA>
What can it be wrong?
Thank you very much for your help
Finally I managed to get what I want with the following lines
w <- which(data>0,arr.ind=TRUE)
data[w] <- names(data)[w[,"col"]] ## esta parte va
data[data==0]<-NA
test<-data.frame(t(data));test$var<-rownames(test)
test2 <- merge(test, data2, by = "var", all.x = TRUE)
test3<-data.frame(lapply(test2[2:(ncol(test2)-1)], function(x)x<-ifelse(is.na(x), x, test2$trat)))
test3<-data.frame(test2$var,test3)
test3<-t(test3)
colnames(test3)<-test3[1,]
test3<-test3[-1,]

Splitting rows with uneven string length into columns in R using tidyr [duplicate]

This question already has answers here:
Split data frame string column into multiple columns
(16 answers)
Closed 6 years ago.
Edit: This was marked as a duplicate. It is not. The question here is not only about splitting a single column into multiple ones, as my separate code would had worked. The main point of my question is splitting the column when the row string possess varying lengths of column output.
I'm trying to turn this:
data <- c("Place1-Place2-Place2-Place4-Place2-Place3-Place5",
"Place7-Place7-Place7-Place7-Place7-Place7-Place7-Place7",
"Place1-Place1-Place1-Place1-Place3-Place5",
"Place1-Place4-Place2-Place3-Place3-Place5-Place5",
"Place6-Place6",
"Place1-Place2-Place3-Place4")
Into this:
X1 X2 X3 X4 X5 X6 X7 X8
1 Place1 Place2 Place2 Place4 Place2 Place3 Place5
2 Place7 Place7 Place7 Place7 Place7 Place7 Place7 Place7
3 Place1 Place1 Place1 Place1 Place3 Place5
4 Place1 Place4 Place2 Place3 Place3 Place5 Place5
5 Place6 Place6
6 Place1 Place2 Place3 Place4
I tried to use tidyr's seperate function using this code:
library(data.table)
data <- as.data.table(data)
data_table <- tidyr::separate(data,
data,
sep="-",
into = strsplit(data$data, "-"),
fill = "right")
Sadly I'm getting this error:
Warning message:
Too many values at 3 locations: 1, 2, 4
What do I need to change to make it work?
You specify the target columns correctly:
library(tidyr)
separate(DF, V1, paste0("X",1:8), sep="-")
which gives:
X1 X2 X3 X4 X5 X6 X7 X8
1 Place1 Place2 Place2 Place4 Place2 Place3 Place5 <NA>
2 Place7 Place7 Place7 Place7 Place7 Place7 Place7 Place7
3 Place1 Place1 Place1 Place1 Place3 Place5 <NA> <NA>
4 Place1 Place4 Place2 Place3 Place3 Place5 Place5 <NA>
5 Place6 Place6 <NA> <NA> <NA> <NA> <NA> <NA>
6 Place1 Place2 Place3 Place4 <NA> <NA> <NA> <NA>
If you don't know how many target columns you need beforehand, you can use:
> max(sapply(strsplit(as.character(DF$V1),'-'),length))
[1] 8
to extract the maximum number of parts (which is thus the number of columns you need).
Several other methods:
splitstackshape :
library(splitstackshape)
cSplit(DF, "V1", sep="-", direction = "wide")
stringi :
library(stringi)
as.data.frame(stri_list2matrix(stri_split_fixed(DF$V1, "-"), byrow = TRUE))
data.table :
library(data.table)
setDT(DF)[, paste0("v", 1:8) := tstrsplit(V1, "-")][, V1 := NULL][]
stringr :
library(stringr)
as.data.frame(str_split_fixed(DF$V1, "-",8))
which all give a similar result.
Used data:
DF <- data.frame(V1=c("Place1-Place2-Place2-Place4-Place2-Place3-Place5",
"Place7-Place7-Place7-Place7-Place7-Place7-Place7-Place7",
"Place1-Place1-Place1-Place1-Place3-Place5",
"Place1-Place4-Place2-Place3-Place3-Place5-Place5",
"Place6-Place6",
"Place1-Place2-Place3-Place4"))

How to split character and numerical separately in R

I have a dataframe which looks like this:
df= data.frame(name= c("1Alex100.00","12Rina Faso92.31","113john00.00"))
And I want to split this into a data frame with 3 columns so that the output looks like:
name1 name2 name3
1 Alex 100.00
12 Rina Faso 92.31
113 john 00.00
I have tried stringr() and grep() and have got limited success. Lack of a delimiter makes it lot more difficult.
You could try
library(tidyr)
res <- extract(df, name, into=c('name1', 'name2', 'name3'),
'(\\d+)([^0-9]+)([0-9.]+)', convert=TRUE)
res
# name1 name2 name3
#1 1 Alex 100.00
#2 2 Rina Faso 92.31
#3 3 john 50.00
str(res)
# 'data.frame': 3 obs. of 3 variables:
#$ name1: int 1 2 3
#$ name2: Factor w/ 3 levels "Alex","john",..: 1 3 2
# $ name3: num 100 92.3 50
Update
Based on 'df' from #DavidArenburg's post
res <- extract(df, name, into=c('name1', 'name2', 'name3'),
'(\\d+)([^0-9]+)([0-9.]+)', convert=TRUE)
res
# name1 name2 name3
#1 121 Réunion 13.76
#2 2 Côte d'Ivoire 22.40
#3 3 john 50.00
Try with str_match from stringr:
str_match(df$name, "^([0-9]*)([A-Za-z ]*)([0-9\\.]*)")
# [,1] [,2] [,3] [,4]
# [1,] "1Alex100.00" "1" "Alex" "100.00"
# [2,] "2Rina Faso92.31" "2" "Rina Faso" "92.31"
# [3,] "3john50.00" "3" "john" "50.00"
So as.data.frame(str_match(df$name, "^([0-9]*)([A-Za-z ]*)([0-9\\.]*)")[,-1]) should give you the desired result.
You could do like this also.
> df <- data.frame(name= c("1Alex100.00","12Rina Faso92.31","113john00.00"))
> x <- do.call(rbind.data.frame, strsplit(as.character(df$name), "(?<=[A-Za-z])(?=\\d)|(?<=\\d)(?=[A-Za-z])", perl=T))
> colnames(x) <- c("name1", "name2", "name3")
> print(x, row.names=FALSE)
name1 name2 name3
1 Alex 100.00
12 Rina Faso 92.31
113 john 00.00
With base R it could be done abit uglier though it works with special characters too
with(df, cbind(sub("\\D.*", "", name),
gsub("[0-9.]", "", name),
gsub(".*[A-Za-z]", "", name)))
# [,1] [,2] [,3]
# [1,] "1" "Alex" "100.00"
# [2,] "2" "Rina Faso" "92.31"
# [3,] "3" "john" "50.00"
An example on special characters
df = data.frame(name= c("121Réunion13.76","2Côte d'Ivoire22.40","3john50.00"))
with(df, cbind(sub("\\D.*", "", name),
gsub("[0-9.]", "", name),
gsub(".*[A-Za-z]", "", name)))
# [,1] [,2] [,3]
# [1,] "121" "Réunion" "13.76"
# [2,] "2" "Côte d'Ivoire" "22.40"
# [3,] "3" "john" "50.00"
Base R not ugly solutions:
proto=data.frame(name1=numeric(),name2=character(),name3=numeric())
strcapture("(\\d+)(\\D+)(.*)",as.character(df$name),proto)
name1 name2 name3
1 1 Alex 100.00
2 12 Rina Faso 92.31
3 113 john 0.00
read.table(text=gsub("(\\d+)(\\D+)(.*)","\\1|\\2|\\3",df$name),sep="|")
V1 V2 V3
1 1 Alex 100.00
2 12 Rina Faso 92.31
3 113 john 0.00
You could use the package unglue :
df <- data.frame(name= c("1Alex100.00","12Rina Faso92.31","113john00.00"))
library(unglue)
unglue_unnest(df, name, "{name1}{name2=\\D+}{name3}", convert = TRUE)
#> name1 name2 name3
#> 1 1 Alex 100.00
#> 2 12 Rina Faso 92.31
#> 3 113 john 0.00

Creating A Dataframe From A Text Dataset

I have a dataset that has hundreds of thousands of fields. The following is a simplified dataset
dataSet <- c("Plnt SLoc Material Description L.T MRP Stat Auto MatSG PC PN Freq Qty CFreq CQty Cur.RPt New.RPt CurRepl NewRepl Updt Cost ServStock Unit OpenMatResb DFStorLocLevel",
"0231 0002 GB.C152260-00001 ASSY PISTON & SEAL/O-RING 44 PD X A A A 18 136 30 29 50 43 24.88 51.000 EA",
"0231 0002 WH.112734 MOTOR REDUCER, THREE-PHAS 41 PD X B B A 16 17 3 3 5 4 483.87 1.000 EA X",
"0231 0002 WH.920569 SPINDLE MOTOR MINI O 22 PD X A A A 69 85 15 9 25 13 680.91 21.000 EA",
"0231 0002 GB.C150583-00001 VALVE-AIR MDI 64 PD X A A A 16 113 50 35 80 52 19.96 116.000 EA",
"0231 0002 FG.124-0140 BEARING 32 PD X A A A 36 205 35 32 50 48 21.16 55.000 EA",
"0231 0002 WP.254997 BEARING,BALL .9843 X 2.04 52 PD X A A A 18 155 50 39 100 58 2.69 181.000 EA"
)
I would like to create a dataframe out of this dataSet for further calculation. The approach I am following is as follows:
I split the dataSet by space and then recombine it.
dataSetSplit <- strsplit(dataSet, "\\s+")
The header (which is the first line) splits correctly and produces 25 characters. This can be seen by the str() function.
str(dataSetSplit)
I will then intend to combine all the rows together using the folloing script
combinedData <- data.frame(do.call(rbind, dataSetSplit))
Please note that the above script "combinedData " errors because the split did not produce equal number of fields.
For this approach to work all the fields must split correctly into 25 fields.
If you think this is a sound approach please let me know how to split the fileds into 25 fields.
It is worth mentioning that I do not like the approach of splitting the data set with the function strsplit(). It is an extremely time consuming step if used with a large data set. Can you please recommend an alternate approach to create a data frame out of the supplied data?
By the looks of it, you have a header row that is actually helpful. You can easily use gregexpr to calculate your "widths" to use with read.fwf.
Here's how:
## Use gregexpr to find the position of consecutive runs of spaces
## This will tell you the starting position of each column
Widths <- gregexpr("\\s+", dataSet[1])[[1]]
## `read.fwf` doesn't need the starting position, but the width of
## each column. We can use `diff` to calculate this.
Widths <- c(Widths[1], diff(Widths))
## Since there are no spaces after the last column, we need to calculate
## a reasonable width for that column too. We can do this with `nchar`
## to find the widest row in the data. From this, subtract the `sum`
## of all the previous values.
Widths <- c(Widths, max(nchar(dataSet)) - sum(Widths))
Let's also extract the column names. We could do this in read.fwf, but it would require us to substitute the spaces in the first line with a "sep" character.
Names <- scan(what = "", text = dataSet[1])
Now, read in everything except the first line. You would use the actual file instead of textConnection, I would suppose.
read.fwf(textConnection(dataSet), widths=Widths, strip.white = TRUE,
skip = 1, col.names = Names)
# Plnt SLoc Material Description L.T MRP Stat Auto MatSG PC PN Freq Qty
# 1 231 2 GB.C152260-00001 ASSY PISTON & SEAL/O-RING 44 PD NA X A A A 18 136
# 2 231 2 WH.112734 MOTOR REDUCER, THREE-PHAS 41 PD NA X B B A 16 17
# 3 231 2 WH.920569 SPINDLE MOTOR MINI O 22 PD NA X A A A 69 85
# 4 231 2 GB.C150583-00001 VALVE-AIR MDI 64 PD NA X A A A 16 113
# 5 231 2 FG.124-0140 BEARING 32 PD NA X A A A 36 205
# 6 231 2 WP.254997 BEARING,BALL .9843 X 2.04 52 PD NA X A A A 18 155
# CFreq CQty Cur.RPt New.RPt CurRepl NewRepl Updt Cost ServStock Unit OpenMatResb
# 1 NA NA 30 29 50 43 NA 24.88 51 EA <NA>
# 2 NA NA 3 3 5 4 NA 483.87 1 EA X
# 3 NA NA 15 9 25 13 NA 680.91 21 EA <NA>
# 4 NA NA 50 35 80 52 NA 19.96 116 EA <NA>
# 5 NA NA 35 32 50 48 NA 21.16 55 EA <NA>
# 6 NA NA 50 39 100 58 NA 2.69 181 EA <NA>
# DFStorLocLevel
# 1 NA
# 2 NA
# 3 NA
# 4 NA
# 5 NA
# 6 NA
Many thanks to Ananda Mahto, he provided many pieces to this answer.
widthMinusFirst <- diff(gregexpr('(\\s[A-Z])+', dataSet[1])[[1]])
widthFirst <- gregexpr('\\s+', dataSet[1])[[1]][1]
Width <- c(widthFirst, widthMinusFirst)
Widths <- c(Width, max(nchar(dataSet)) - sum(Width))
columnNames <- scan(what = "", text = dataSet[1])
read.fwf(textConnection(dataSet[-1]), widths = Widths, strip.white = FALSE,
skip = 0, col.names = columnNames)

R: fragment a list

I am kind of tired of working with lists..and my limited R capabilities ... I could not solve this from long time...
My list with multiple dataframe looks like the following:
set.seed(456)
sn1 = paste( "X", c(1:4), sep= "")
onelist <- list (df1 <- data.frame(sn = sn1, var1 = runif(4)),
df2 <- data.frame(sn = sn1, var1 = runif(4)),
df3 <- data.frame(sn = sn1,var1 = runif(4)))
[[1]]
sn var1
1 X1 0.3852362
2 X2 0.3729459
3 X3 0.2179086
4 X4 0.7551050
[[2]]
sn var1
1 X1 0.8216811
2 X2 0.5989182
3 X3 0.6510336
4 X4 0.8431172
[[3]]
sn var1
1 X1 0.4532381
2 X2 0.7167571
3 X3 0.2912222
4 X4 0.1798831
I want make a subset list in which the row 2 and 3 are only present.
srow <- c(2:3) # just I have many rows in real data
newlist <- lapply(onelist, function(y) subset(y, row(y) == srow))
The newlist is empty....
> newlist
[[1]]
[1] sn var1
<0 rows> (or 0-length row.names)
[[2]]
[1] sn var1
<0 rows> (or 0-length row.names)
[[3]]
[1] sn var1
<0 rows> (or 0-length row.names)
Help please ....
Does this do it?
Note the comma after the rows which implicitly is interpreted as NULL and results in the extraction all of the columns:
> lapply(onelist, "[", c(2,3),)
[[1]]
sn var1
2 X2 0.2105123
3 X3 0.7329553
[[2]]
sn var1
2 X2 0.33195997
3 X3 0.08243274
[[3]]
sn var1
2 X2 0.3852362
3 X3 0.3729459
You could have gotten your subset strategy to work with:
lapply(onelist, function(y) subset(y, rownames(y) %in% srow ))
Note that many time people use "==" when they really should be using %in%
?match
I don't think the row function does what you think it does:
Returns a matrix of integers indicating their row number in a matrix-like object, or a factor indicating the row labels.
Looking at what it returns on the list you have
> row(onelist[[1]])
[,1] [,2]
[1,] 1 1
[2,] 2 2
[3,] 3 3
[4,] 4 4
> row(onelist[[1]])==srow
[,1] [,2]
[1,] FALSE FALSE
[2,] FALSE FALSE
[3,] FALSE FALSE
[4,] FALSE FALSE
You are doing a simple subset of the data.frames, so you can just use
newlist <- lapply(onelist, function(y) y[srow,])
which gives
> newlist
[[1]]
sn var1
2 X2 0.2105123
3 X3 0.7329553
[[2]]
sn var1
2 X2 0.33195997
3 X3 0.08243274
[[3]]
sn var1
2 X2 0.3852362
3 X3 0.3729459