How to find specific strings in dataframe using for loop? - r

I'm using for loop to find all specific strings (df2$x2) in another dataframe (df1$x1) and what my purpose is create new column the df1$test and write the df$x2 value.
For example:
df1 <- data.frame(x1 = c("TE-T6-3 XYZ12X","TE-D31L-2 QWE12X","TE-H6-1 ABC12X","TE-D31L-2 QWE12X","EC20 QWX12X"),
Y = c(2017,2017,2018,2018,2017),
Sales = c(25,50,30,40,90))
df1$x1 <- as.character(as.factor(df1$x1))
df2 <- data.frame(x2 = c("TE-T6-5","TE-D31L-2","TE-H6-15","EC500","EC20","TE-D31L-2"),
Y = c(2018,2017,2018,2017,2018,2018),
P = c(100,300,200,50,150,300))
df2$x2 <- as.character(as.factor(df2$x2))
for(i in 1:nrow(df2)){
f <- df2[i,1]
df1$test <- ifelse(grepl(f, df1$x1),f,"not found")
}
What should I do after the end of loop? I know that problem is y is refreshing every time. I tried "if" statement to create new data frame and save outputs but it didn't work. It's writing only one specific string.
Thank you in advance.
Expected output:
df1 <- data.frame(x1 = c("TE-T6-3 XYZ12X","TE-D31L-2 QWE12X","TE-H6-1 ABC12X","TE-D31L-2 QWE12X","EC20 QWX12X"),
output = c("not found","TE-D31L-2","not found","TE-D31L-2","EC20"))

Do you want to have one new column for each string? if that is what you need, your code should be:
df1 <- data.frame(x1 = c("TE-T6-3 XYZ12X","TE-D31L-2 QWE12X","TE-H6-1 ABC12X","TE-D31L-2 QWE12X","EC20 QWX12X"),
Y = c(2017,2017,2018,2018,2017),
Sales = c(25,50,30,40,90))
df1$x1 <- as.character(as.factor(df1$x1))
df2 <- data.frame(x2 = c("TE-T6-5","TE-D31L-2","TE-H6-15","EC500","EC20","TE-D31L-2"),
Y = c(2018,2017,2018,2017,2018,2018),
P = c(100,300,200,50,150,300))
df2$x2 <- as.character(as.factor(df2$x2))
for(i in 1:nrow(df2)){
f <- df2[i,1]
df1$test <- ""
df1$test<-ifelse(grepl(f, df1$x1),T,F)
colnames(df1) <- c(colnames(df1[1:length(df1[1,])-1]),f)
}
it creates a new column with a temp name and then rename it with the string evaluated. Also i change "not found" for F, but you can use whatever you want.
[EDIT:]
If you want that expected output, you can use this code:
df1 <- data.frame(x1 = c("TE-T6-3 XYZ12X","TE-D31L-2 QWE12X","TE-H6-1 ABC12X","TE-D31L-2 QWE12X","EC20 QWX12X"),
Y = c(2017,2017,2018,2018,2017),
Sales = c(25,50,30,40,90))
df1$x1 <- as.character(as.factor(df1$x1))
df2 <- data.frame(x2 = c("TE-T6-5","TE-D31L-2","TE-H6-15","EC500","EC20","TE-D31L-2"),
Y = c(2018,2017,2018,2017,2018,2018),
P = c(100,300,200,50,150,300))
df2$x2 <- as.character(as.factor(df2$x2))
df1$output <- "not found"
for(i in 1:nrow(df2)){
f <- df2[i,1]
df1$output[grepl(f, df1$x1)]<-f
}
Very similar of what you have done, but it was needed to index which rows you have to write.
This only works when the data only can have one match, it is a little more complicated if you can have more than one match for row. But i think that's not your problem.

You simply need to split the df1$x1 strings on space and merge (or match since you are only interested in one variable)on df2$x2, i.e.
v1 <- sub('\\s+.*', '', df1$x1)
v1[match(v1, df2$x2)]
#[1] NA "TE-D31L-2" NA "TE-D31L-2" "EC20"

Related

Extract a value from a dataframe iteratively (R)

I have a function to select a value from a dataframe. I want to select that value, save it, remove it from the dataset, and select a value using the same function from the remaining values in the dataframe. What is the best way to do this?
Here is a simple example:
V1 <- c(5,6,7,8,9,10)
df <- data.frame(V1)
V2 <- as.data.frame(matrix(nrow=3,ncol=1))
maximum <- function(x){
max(x)
}
V2[i,]<- maximum(df)
df <- anti_join(df,V2,by='V1')
How can I set this up such that I reapply the maximum function to the remaining values in df and save these values in in V2?
I'm using a different and more complex set of functions and if/else statements than max - this is just an example. I do have to reapply the function to the remaining values, because I will be using the function on a new dataframe if df is empty.
Is this what you're looking for?
V1 <- data.frame(origin = c(5,6,7,8,9,10))
V2 <- as.data.frame(matrix(nrow=3,ncol=1))
df1 <- V1
df2 <- V2
recursive_function <- function(df1,df2,depth = 3,count = 1){
if (count == depth){
# Find index
indx <- which.max(df1[,1])
curVal <- df1[indx,1]
df2[count,1] <- curVal
df1 <- df1[-indx, ,drop = FALSE]
return(list(df1,
df2))
} else {
# Find index
indx <- which.max(df1[,1])
# Find Value
curVal <- df1[indx,1]
# Add value to new data frame
df2[count,1] <- curVal
# Subtract value from old dataframe
df1 <- df1[-indx, ,drop = FALSE]
recursive_function(df1,df2,depth,count + 1)
}
}
recursive_function(df1,df2)
Here is another solution that I stumbled across:
V1 <- c(5,6,7,8,9,10)
df <- data.frame(V1)
minFun <- function(df, maxRun){
V2 <- as.data.frame(matrix(nrow=maxRun,ncol=1))
for(i in 1:maxRun){
V2[i,]<- min(df)
df <- dplyr::anti_join(df,V2,by='V1')
}
return(V2)
}
test <- minFun(df = df, maxRun = 3)
test

Simplifying a function that performs operations on one data frame based on values in another data frame

I have two data frames dat1 and dat2:
dat1 <- data.frame(id = rep(c("a","b","c"), each =100),
dist = rep(1:100, times = 3),
var1 = rnorm(300),
var2 = rnorm(300))
dat2 <- data.frame(id = c("a","b","c"),
value = c(42,56,39))
the value column in dat2 contains the index of the values through which I would like to subset in dat1. I wrote the following function getv to do this subset and perform this operation using that value:
getk <-
function(id, value){
x <- dplyr::filter(dat1, id == id)
x <- x[1:value, ]
k = 10*(value^(2/9))
k = ceiling(k)
k
}
getk(a,42)
I want to add a line to the function that assigns the correct value from dat2 to a new object v, so that I don't have to feed the function the id and value every time. I cannot figure out how to say essentially: "if I give tell you I want to do this for a, assign the number from dat2$value that goes with filter(dat2, id==a) to the object v"
In other words, my function will turn into something close to this:
getk <-
function(id){
x <- dplyr::filter(dat1, id == id)
v <- #the value in dat2
x <- x[1:v, ]
k = 10*(v^(2/9))
k = ceiling(k)
k
}
#after which I could just do this and get the same answer as above:
getk(a)
`
I believe you want
v <- dat2$value[dat2$id == id]
But note it will only work in your function if you use getk("a") since a is not an object.

Apply a user defined function to a list of data frames

I have a series of data frames structured similarly to this:
df <- data.frame(x = c('notes','year',1995:2005), y = c(NA,'value',11:21))
df2 <- data.frame(x = c('notes','year',1995:2005), y = c(NA,'value',50:60))
In order to clean them I wrote a user defined function with a set of cleaning steps:
clean <- function(df){
colnames(df) <- df[2,]
df <- df[grep('^[0-9]{4}', df$year),]
return(df)
}
I'd now like to put my data frames in a list:
df_list <- list(df,df2)
and clean them all at once. I tried
lapply(df_list, clean)
and
for(df in df_list){
clean(df)
}
But with both methods I get the error:
Error in df[2, ] : incorrect number of dimensions
What's causing this error and how can I fix it? Is my approach to this problem wrong?
You are close, but there is one problem in code. Since you have text in your dataframe's columns, the columns are created as factors and not characters. Thus your column naming does not provide the expected result.
#need to specify strings to factors as false
df <- data.frame(x = c('notes','year',1995:2005), y = c(NA,'value',11:21), stringsAsFactors = FALSE)
df2 <- data.frame(x = c('notes','year',1995:2005), y = c(NA,'value',50:60), stringsAsFactors = FALSE)
clean <- function(df){
colnames(df) <- df[2,]
#need to specify the column to select the rows
df <- df[grep('^[0-9]{4}', df$year),]
#convert the columns to numeric values
df[, 1:ncol(df)] <- apply(df[, 1:ncol(df)], 2, as.numeric)
return(df)
}
df_list <- list(df,df2)
lapply(df_list, clean)

Vectorization of a nested for-loop that inputs all paired combinations

I thought that the following problem must have been answered or a function must exist to do it, but I was unable to find an answer.
I have a nested loop that takes a row from one 3-col. data frame and copies it next to each of the other rows, to form a 6-col. data frame (with all possible combinations). This works fine, but with a medium sized data set (800 rows), the loops take forever to complete the task.
I will demonstrate on a sample data set:
Sdat <- data.frame(
x = c(10,20,30,40),
y = c(15,25,35,45),
ID =c(1,2,3,4)
)
compar <- data.frame(matrix(nrow=0, ncol=6)) # to contain all combinations
names(compar) <- c("x","y", "ID", "x","y", "ID")
N <- nrow(Sdat) # how many different points we have
for (i in 1:N)
{
for (j in 1:N)
{
Temp1 <- Sdat[i,] # data from 1st point
Temp2 <- Sdat[j,] # data from 2nd point
C <- cbind(Temp1, Temp2)
compar <- rbind(C,compar)
}
}
These loops provide exactly the output that I need for further analysis. Any suggestion for vectorizing this section?
You can do:
ind <- seq_len(nrow(Sdat))
grid <- expand.grid(ind, ind)
compar <- cbind(Sdat[grid[, 1], ], Sdat[grid[, 2], ])
A naive solution using rep (assuming you are happy with a data frame output):
compar <- data.frame(x = rep(Sdat$x, each = N),
y = rep(Sdat$y, each = N),
id = rep(1:n, each = N),
x1 = rep(Sdat$x, N),
y1 = rep(Sdat$y, N),
id_1 = rep(1:n, N))

multiply all columns in data frame in R

I need to multiply all columns in a data frame with each other. As an example, I need to achieve the following:
mydata$C1_2<-mydata$sic1*mydata$sic2
but for all my columns with values going from 1 to 733 (sic1, sic2, sic3,..., sic733).
I've tried the following but it doesn't work:
for(i in 1:733){
for(j in 1:733){
mydata$C[i]_[j]<-mydata$sic[i]*mydata$sic[j]
}
}
Could you help me? Thanks for your help.
Despite the question if you really want what you think you want, I feel like this could help:
df <- data.frame(
a = 1:4
, b = 1:4
, c = 4:1
)
multiplyColumns <- function(name1, name2, df){
df[, name1] * df[, name2]
}
combinations <- expand.grid(names(df), names(df), stringsAsFactors = FALSE)
names4result <- paste(combinations[,1], combinations[,2], sep = "_")
result <- as.data.frame(mapply(multiplyColumns, combinations[,1], combinations[,2], MoreArgs = list(df = df)))
names(result) <- names4result
result

Resources