R - create iterable list/dataframe from unique() - r

I'd like to get the unique elements from a column. That seems straight forward. Both of these work, but I'm not getting the object type I'd like:
userlist <- as.list(somebigdf$username)
userlist <- unique(userlist)
or
userlist <- unique(somebigdf$username)
When I iterate through, I'm not getting the names:
for(i in 1:length(userlist)){
cat(names(userlist[i]), '\n')
}
Returns blank spaces.
for(i in userlist){
cat(i, '\n')
}
Returns integers.
The above function is just an example. I'll be using that but also matching the returned name in an if-else function.
The object types seem to be integers or an extended data.frame with lots of values for each name - which isn't what I want. I would really just like a list of strings something along the lines of userlist = c( the results from unique).
Edit -
This code will iterate correctly through the names:
for(name in unique(somebigdf$username)){
cat(name, '\n')
}

I'm accepting my own answer. Namely, a working solution - this code will iterate correctly through the names:
for(name in unique(somebigdf$username)){
cat(name, '\n')
}
If someone at a later date has a better answer that seems more in keeping with the question, I will be happy to accept that as the answer.

Related

Unable to update data in dataframe

i tried updating data in dataframe but its unable to get updating
//Initialize data and dataframe here
user_data=read.csv("train_5.csv")
baskets.df=data.frame(Sequence=character(),
Challenge=character(),
countno=integer(),
stringsAsFactors=FALSE)
/Updating data in dataframe here
for(i in 1:length((user_data)))
{
for(j in i:length(user_data))
{
if(user_data$challenge_sequence[i]==user_data$challenge_sequence[j]&&user_data$challenge[i]==user_data$challenge[j])
{
writedata(user_data$challenge_sequence[i],user_data$challenge[i])
}
}
}
writedata=function( seqnn,challng)
{
#print(seqnn)
#print(challng)
newRow <- data.frame(Sequence=seqnn,Challenge=challng,countno=1)
baskets.df=rbind(baskets.df,newRow)
}
//view data here
View(baskets.df)
I've modified your code to what I believe will work. You haven't provided sample data, so I can't verify that it works the way you want. I'm basing my attempt here on a couple of common novice mistakes that I'll do my best to explain.
Your writedata function was written to be a little loose with it's scope. When you create a new function, what happens in the function technically happens in its own environment. That is, it tries to look for things defined within the function, and then any new objects it creates are created only within that environment. R also has this neat (and sometimes tricky) feature where, if it can't find an object in an environment, it will try to look up to the parent environment.
The impact this has on your writedata function is that when R looks for baskets.df in the function and can't find it, R then turns to the Global Environment, finds baskets.df there, and then uses it in rbind. However, the result of rbind gets saved to a baskets.df in the function environment, and does not update the object of the same name in the global environment.
To address this, I added an argument to writedata that is simply named data. We can then use this argument to pass a data frame to the function's environment and do everything locally. By not making any assignment at the end, we implicitly tell the function to return it's result.
Then, in your loop, instead of simply calling writedata, we assign it's result back to baskets.df to replace the previous result.
for(i in 1:length((user_data)))
{
for(j in i:length(user_data))
{
if(user_data$challenge_sequence[i] == user_data$challenge_sequence[j] &&
user_data$challenge[i] == user_data$challenge[j])
{
baskets.df <- writedata(baskets.df,
user_data$challenge_sequence[i],
user_data$challenge[i])
}
}
}
writedata=function(data, seqnn,challng)
{
#print(seqnn)
#print(challng)
newRow <- data.frame(Sequence = seqnn,
Challenge = challng,
countno = 1)
rbind(data, newRow)
}
I'm not sure what you're programming background is, but your loops will be very slow in R because it's an interpreted language. To get around this, many functions are vectorized (which simply means that you give them more than one data point, and they do the looping inside compiled code where the loops are fast).
With that in mind, here's what I believe will be a much faster implementation of your code
user_data=read.csv("train_5.csv")
# challenge_indices will be a matrix with TRUE at every place "challenge" and "challenge_sequence" is the same
challenge_indices <- outer(user_data$challenge_sequence, user_data$challenge_sequence, "==") &
outer(user_data$challenge, user_data$challenge, "==")
# since you don't want duplicates, get rid of them
challenge_indices[upper.tri(challenge_indices, diag = TRUE)] <- FALSE
# now let's get the indices of interest
index_list <- which(challenge_indices,arr.ind = TRUE)
# now we make the resulting data set all at once
# this is much faster, because it does not require copying the data frame many times - which would be required if you created a new row every time.
baskets.df <- with(user_data, data.frame(
Sequence = challenge_sequence[index_list[,"row"]],
challenge = challenge[index_list[,"row"]]
)

Need assistance with understanding R for loop error: unexpected '}' in " }"

Just to give some background first:
I currently have 2 data frames (giraffe, leaf) and both of them share the column 'key', where the elements in the leaf data frame are a subset of giraffe. What I needed to do is compare the two data frames and when there are matching elements in both data frames in the 'key' column, the string 'leaf' will be input into another column (project) in the giraffe data frame inside the same row as the matching 'key' element. I've taken the following approach however it seems I have made a small error somewhere and after searching online, I still don't know what it is:
Truth_vector <- is.element((giraffe[,1]),(leaf[,1])) #returns a vector with 3000 elements, most are FALSE except for where the element inside 'key' is present in both data frames
i=1
for (i in 1:length(giraffe[,1])) {
if Truth_vector[i] == TRUE {
giraffe[i,5] <- 'leaf'
}
i = i+1
}
Error: unexpected '}' in "}"
Edit:
I tried implementing the solution as a function however nothing ends up happening, no error messages get returned either. What I've done is:
Project_assign <- function(prjct) {
Truth_vector <- is.element((giraffe[,1]),(prjct[,1]))
giraffe[which(Truth_vector),5] <- 'prjct'
}
Project_assign(leaf)
Edit: This was because everything was getting assigned in the function sub environment, not the global environment. Using assign('giraffe',giraffe,envir=.GlobalEnv) solves this however you should try and avoid the assign function and Instead I used a for loop going over a list of all the dataframes
You have a couple issues. First, the if criteria needs to be in parentheses, and secondly you don't need to increment i yourself. This should suffice:
for (i in 1:length(giraffe[,1])) {
if (Truth_vector[i] == TRUE) {
giraffe[i,5] <- 'leaf'
}
}
Of course, this would do it too:
giraffe[which(Truth_vector),5] <- 'leaf'
(assuming Truth_vector is not longer than the number of rows in giraffe)

Getting Error "could not find function "assign<-" inside of colnames()

I'm using assign() to assign some new data frames from some other data frame. I then want to name some of the columns in the new data frame. When I use assign() to create the new data frames it works fine. But when I use the assign() inside of colnames() is gives the error 'Error "could not find function "assign<-".'
Here's my snippet of code(abbreviated of course):
for(i in 1:value) {
assign(Name[i], Old.Data.Frame[Old.Data.Frame$1 == Index[i]]) #I'm going to call this line of code 'New Data Frame' for brevity
for(j in 1:ncol(New Data Frame)) {
colnames(New Data Frame)[j] = as.character(Old.Data.Frame[3,j])
I do all this assign() stuff because the names of the Old Data Frame constantly change and I can create any concrete variables in my code, only the dimentions of the frame stay the same.
The only error in this code is that R cannot "find function assign<- in colnames(...". I'm flustered because assign() had just worked in the line before, any help is appreciated, thanks!
You have a list of variable names in Name, which you assign a value (your code block).
for(i in 1:value) { assign(Name[i], Old.Data.Frame[Old.Data.Frame$1 == Index[i]]) }
Could you then try (note I'm separating this code block for debugging purposes):
for(i in 1:value) { colnames(get(Names[i])) <- as.character(Old.Data.Frame[3,] }
get will retrieve the data (data.frame) assigned to the variable name Names[i] (character)

Loop works outside function but in functions it doesn't.

Been going around for hours with this. My 1st question online on R. Trying to creat a function that contains a loop. The function takes a vector that the user submits like in pollutantmean(4:6) and then it loads a bunch of csv files (in the directory mentioned) and binds them. What is strange (to me) is that if I assign the variable id and then run the loop without using a function, it works! When I put it inside a function so that the user can supply the id vector then it does nothing. Can someone help ? thank you!!!
pollutantmean<-function(id=1:332)
{
#read files
allfiles<-data.frame()
id<-str_pad(id,3,pad = "0")
direct<-"/Users/ped/Documents/LearningR/"
for (i in id) {
path<-paste(direct,"/",i,".csv",sep="")
file<-read.csv(path)
allfiles<-rbind(allfiles,file)
}
}
Your function is missing a return value. (#Roland)
pollutantmean<-function(id=1:332) {
#read files
allfiles<-data.frame()
id<-str_pad(id,3,pad = "0")
direct<-"/Users/ped/Documents/LearningR/"
for (i in id) {
path<-paste(direct,"/",i,".csv",sep="")
file<-read.csv(path)
allfiles<-rbind(allfiles,file)
}
return(allfiles)
}
Edit:
Your mistake was that you did not specify in your function what you want to get out from the function. In R, you create objects inside of function (you could imagine it as different environment) and then specify which object you want it to return.
With my comment about accepting my answer, I meant this: (...To mark an answer as accepted, click on the check mark beside the answer to toggle it from greyed out to filled in...).
Consider even an lapply and do.call which would not need return being last line of function:
pollutantmean <- function(id=1:332) {
id <- str_pad(id,3,pad = "0")
direct_files <- paste0("/Users/ped/Documents/LearningR/", id, ".csv")
# READ FILES INTO LIST AND ROW BIND
allfiles <- do.call(rbind, lapply(direct_files, read.csv))
}
ok, I got it. I was expecting the files that are built to be actually created and show up in the environment of R. But for some reason they don't. But R still does all the calculations. Thanks lot for the replies!!!!
pollutantmean<-function(directory,pollutant,id)
{
#read files
allfiles<-data.frame()
id2<-str_pad(id,3,pad = "0")
direct<-paste("/Users/pedroalbuquerque/Documents/Learning R/",directory,sep="")
for (i in id2) {
path<-paste(direct,"/",i,".csv",sep="")
file<-read.csv(path)
allfiles<-rbind(allfiles,file)
}
#averaging polutants
mean(allfiles[,pollutant],na.rm = TRUE)
}
pollutantmean("specdata","nitrate",23:35)

Error: missing value where True/False

I am trying to delete all values in a list that have the tag ".dsw". My list is a list of files using the function list.files. This is my code:
for (file in GRef) {
if (strsplit(file, "[.]")[[1]][3] == "dsw") {
#GRef=GRef[-file]
for(n in 1:length(GRef)){
if (GRef[n] == file){
GRef=GRef[-n]
}
}
}
}
Where GRef is the list of file names. I get the error listed above, but I dont understand why. I have looked at this post: Error .. missing value where TRUE/FALSE needed, but I dont think it is the same thing.
You shouldn't attempt to to modify a vector while you are looping over it. The problem is your are removing items you are then trying to extract later which is causing the missing values. It's better to identify all the items you want remove first, then remove them. For example
GRef <- c("a.file.dsw", "b.file.txt", "c.file.gif", "d.file.dsw")
exts <- sapply(strsplit(GRef, "[.]"), `[`, 3)
GRef <- GRef[exts!="dsw"]

Resources