Replacement Function - r

x <- c(22,33,45)
erase <- function(x, value) {
x[!x %in% value]
}
erase(x, 45)
it prints output as 22, 33
Can anybody describe how this code removes 45 from vector x?
let say vector x <- c(33, 22, 45)
In the earlier code the function body says, take index of x and inside the index don't keep the value matched with x. If say the value is 45 and it removed from x inside the indexing then in outer of indexing i.e. x [ ] how it restoring the 33 and 22 and producing output 33 22 as it is index values. I'm little bit confused with this function, how actually it keeping the index 1 and 2 as 33 and 22.
why not it returning x[33,22] which provides NA values but actually it taking the values like x[1,2] excluding the 33 at 3rd index position.
May be I'm not getting it properly. Can anyone please elaborate how the code is producing 33 and 22 as output?
**** This code is for R programming language.

see ?'%in%'.
The vector x %in% 45 checks whether each element of x is in 45 and records TRUE if it is, else FALSE (since 45 is a single value, this is the same as x == 45).
So x %in% 45 == c(FALSE, FALSE, TRUE)
Then the ! operator reverses logical values, so
! x %in% 45 == c(TRUE, TRUE, FALSE)
When you subset by entering a logical vector in [], the values of the vector whose indexes correspond to the value FALSE in the logical vector are removed. In this case, only 45 has an index (3) whose value in the logical vector is FALSE, so it is removed.

Related

drawing a value from a vector r

After removing the values from the vector from 1 to 100 I have the following vector:
w
[1] 2 5 13 23 24 39 41 47 48 51 52 58 61 62 70 71 72 90
I am now trying to draw values from this vector with the sample function
for(x in roznica)
{
if(licznik_2 != licznik_1 )
{
roznica_proces_2 <- sample(1:w, roznica)
} else {
roznica_proces_2 <- NA
}
}
I tried various combinations with the sample
If w is the name of the vector then you would NOT use sample(1:w, ...). For one thing 1:w doesn't really amke sense since the : operator expects its second argument to be a single number, while w is apparently on the order of 15 values. Depending on what roznica is (and hopefully it is a single integer) then you might use:
sample(w, roznica) # returns a vector of length roznica's value of randomly ordered values in `w`.
The other problem is that you are currently overwirign any values from prior iterations of the for loop. So you might want to use:
roznica_proces_2[roznica] <- sample(1:w, roznica)
You would of course need to have initialized roznica_proces_2, perhaps with:
roznica_proces_2 <- list()
Regarding your query in the comment :
I am only concerned with the sample function itself: I will show an example : w [1] 31 and now I want to draw 1 number from that in ( which is 31) proces_nr_2 <- sample(w, 1) What does he get? proces_nr_2 [1] 26
The reason that happens is because when a vector is of length 1 the sampling takes from 1 to that number. It is explained in the help page of ?sample.
If x has length 1, is numeric (in the sense of is.numeric) and x >= 1, sampling via sample takes place from 1:x
So if you have only 1 number to sample just return that number directly instead of passing it in sample.

ifelse statement with string

double="true"
data=data.frame("var1"=c(1:10))
data$var2=ifelse(double=="true",2*data$var1,NA)
data$var2want=2*data$var1
I have a character that stores into double as "true" if I want to double a variable. In this example I start with var1 equal to 1:10. double="true". So I want to make var2 equals to (1:10)*2. The desired output is var2want. However, when I apply my ifelse statement I just get var2=2 for all values. I am not sure how to fix this issue.
double is of length 1
length(double)
#[1] 1
whereas
length(data$var1)
#[1] 10
while using ifelse it returns the value which is of same length as test as
double == "true"
returns a vector of length 1, hence you get only one value back which is the first value of calculation
2*data$var1[1]
#[1] 2
and this value is recycled across all values.
For ifelse to work for all value we need to somehow make the length equal
ifelse(rep(double == "true", length(data$var1)), 2*data$var1, NA)
#[1] 2 4 6 8 10 12 14 16 18 20
However, if you have only one value to compare it is better to use simple if/else instead of ifelse
data$var2 <- if (double == "true") 2*data$var1 else NA

Get ranges of dataframe given an input value (i.e. 1 returns df[1:10,])

I have a dataframe df, and I want to create a function in R that returns ranges of 10 entries of the dataframe given an input number. That is:
If input number is equal to 1, the function returns df[1:10,]
If input number is equal to 2, the function returns df[11:20,]
If input number is equal to 3, the function returns df[21:30,]
...
Like they were pages: page 1 shows ten entries, page 2 shows next ten entries, and so on.
Note:
if there're no more "ten entries" to return, the function should return all what's left in the dataframe
the lenght of the dataframe is not fixed (i.e. the function asks for the df to use and the "page" to return).
It looks pretty simple to implement but I cannot figure out how to do it in a proper and fast way.
Edit
I meant returning the rows not columns, sorry. Just edited. But #Freakazoid solution does more or less the trick, just changing the ncol by nrow (see his solution below)
The following function does the trick:
df <- data.frame(matrix(rnorm(1020), nrow=54, ncol=3))
batch_df <- function(df, batch_part) {
nbr_row <- nrow(df)
batch_size <- 10
nbr_of_batchs <- as.integer(nbr_row/batch_size)
last_batch_size <- (nbr_row - nbr_of_batchs*batch_size)
batch_indizes <- c(rep(1:nbr_of_batchs, each=batch_size),
rep(nbr_of_batchs+1, last_batch_size))
if(all(batch_part %in% batch_indizes)) {
row_index <- which(batch_indizes %in% c(batch_part))
ret_df <- df[ row_index,]
} else {
ret_df <- data.frame()
}
return(ret_df)
}
batch_df(df, 3)
The function first defines indices for rows. With these indices the function will search for the batch_part you want to select.
The function can not only take a single number; it can be a vector given where you can select multiple batch parts at once.
Output:
X1 X2 X3
21 0.7168950 0.88057886 0.1659177
22 -1.0560819 -0.53230247 -0.4204708
23 0.4835649 -1.43453719 0.1563253
24 0.1266011 1.22149179 -0.7924120
25 0.3982262 -0.59821992 -1.1645105
26 -0.4809448 0.42533877 0.2359328
27 -0.1530060 -0.23762552 0.9832919
28 0.8808083 -0.06004995 -1.0810818
29 -0.2924377 -1.23812802 -0.9057353
30 -0.2420152 -0.52037258 0.7406486
Given input number i, try
j <- i * 10
max <- pmin(j, nrow(df))
df[(j-9):max, ]

Remove All Columns where the last row is not equal to specific value x [duplicate]

This question already has an answer here:
Subset columns based on row value
(1 answer)
Closed 4 years ago.
I have a data frame(DF) that is like so:
DF <- rbind (c(10,20,30,40,50), c(21,68,45,33,21), c(11,98,32,10,30), c(50,70,70,70,50))
10 20 30 40 50
21 68 45 33 21
11 98 32 10 30
50 70 70 70 50
In my scenario my x would be 50. So my resulting dataframe(resultDF) will look like this:
10 50
21 21
11 30
50 50
How Can I do this in r? I have attempted using subset as below but it doesn't seem to work as I am expecting:
resultDF <- subset(DF, DF[nrow(DF),] == 50)
Error in x[subset & !is.na(subset), vars, drop = drop] :
(subscript) logical subscript too long
I have solved it. My sub setting was function was inaccurate. I used the following piece of code to get the results I needed.
resultDF <- DF[, DF[nrow(DF),] == 50]
Your issue with subset() was only about the syntax for calling it with a logical column vector (its third arg, not its second). You can either use subset() or plain logical indexing. The latter is recommended.
The help page ?subset tells you its optional second arg ('subset') is a logical row-vector, and its optional third arg ('select') is a logical column-vector:
subset: logical expression indicating elements or rows to keep:
missing values are taken as false.
select: expression, indicating columns to select from a data frame.
So you want to call it with this logical column-vector:
> DF[nrow(DF),] == 50
[1] TRUE FALSE FALSE FALSE
There are two syntactical ways to leave subset()'s second arg default and pass the third arg:
# Explicitly pass the third arg by name...
> subset(DF, select=(DF[nrow(DF),] == 50) )
# Leave 2nd arg empty, it will default (to NULL)...
> subset(DF, , (DF[nrow(DF),] == 50) )
[,1] [,2]
[1,] 10 50
[2,] 21 21
[3,] 11 30
[4,] 50 50
The second way is probably preferable as it looks like generic row,col-indexing, and also doesn't require you to know the third arg's name.
(As a mnemonic, in R and SQL terminology, understand that 'select' implicitly means 'column-indices', and 'filter'/'subset' implicitly means 'row-indices'. Or in data.table terminology they're called i-indices, j-indices respectively.)

Problems subsetting columns based on values from two separate dataframes

I am using data obtained from a spatially gridded system, for example a city divided up into equally spaced squares (e.g. 250m2 cells). Each cell possesses a unique column and row number with corresponding numerical information about the area contained within this 250m2 square (say temperature for each cell across an entire city). Within the entire gridded section (or the example city), I have various study sites and I know where they are located (i.e. which cell row and column each site is located within). I have a dataframe containing information on all cells within the city, but I want to subset this to only contain information from the cells where my study sites are located. I previously asked a question on this 'Matching information from different dataframes and filtering out redundant columns'. Here is some example code again:
###Dataframe showing cell values for my own study sites
Site <- as.data.frame(c("Site.A","Site.B","Site.C"))
Row <- as.data.frame(c(1,2,3))
Column <- as.data.frame(c(5,4,3))
df1 <- cbind(Site,Row, Column)
colnames(df1) <- c("Site","Row","Column")
###Dataframe showing information from ALL cells
eg1 <- rbind(c(1,2,3,4,5),c(5,4,3,2,1)) ##Cell rows and columns
eg2 <- as.data.frame(matrix(sample(0:50, 15*10, replace=TRUE), ncol=5)) ##Numerical information
df2 <- rbind(eg1,eg2)
rownames(df2)[1:2] <- c("Row","Column")
From this, I used the answer from the previous questions which worked perfectly for the example data.
output <- df2[, (df2['Row', ] %in% df1$Row) & (df2['Column', ] %in% df1$Column)]
names(output) <- df1$Site[mapply(function(r, c){which(r == df1$Row & c == df1$Column)}, output[1,], output[2,])]
However, I cannot apply this to my own data and cannot figure out why.
EDIT: Initially, I thought there was a problem with naming the columns (i.e. the 'names' function). But it would appear there may be an issue with the 'output' line of code, whereby columns are being included from df2 that shouldn't be (i.e. the output contained columns from df2 which possessed column and row numbers not specified within df1).
I have also tried:
output <- df2[, (df2['Row', ] == df1$Row) & (df2['Column', ] == df1$Column)]
But when using my own (seemingly comparable) data, I don't get information from all cells specified in the 'df1' equivalent (although again works fine in the example data above). I can get my own data to work if I do each study site individually.
SiteA <- df2[, which(df2['Row', ] == 1) & (df2['Column', ] == 5)]
SiteB <- df2[, which(df2['Row', ] == 2) & (df2['Column', ] == 4)]
SiteC <- df2[, which(df2['Row', ] == 3) & (df2['Column', ] == 3)]
But I have 1000s of sites and was hoping for a more succinct way. I am sure that I have maintained the same structure, double checked spellings and variable names. Would anyone be able to shed any light on potential things which I could be doing wrong? Or failing this an alternative method?
Apologies for not providing an example code for the actual problem (I wish I could pinpoint what the specific problem is, but until then the original example is the best I can do)! Thank you.
The only apparent issue I can see is that mapply is not wrapped around unlist. mapply returns a list, which is not what you're after for subsetting purposes. So, try:
output <- df2[, (df2['Row', ] %in% df1$Row) & (df2['Column', ] %in% df1$Column)]
names(output) <- df1$Site[unlist(mapply(function(r, c){which(r == df1$Row & c == df1$Column)}, output[1,], output[2,]))]
Edit:
If the goal is to grab columns whose first 2 rows match the 2nd and 3rd elements of a given row in df1, you can try the following:
output_df <- Filter(function(x) !all(is.na(x)), data.frame(do.call(cbind,apply(df2, 2, function(x) {
##Create a condition vector for an if-statement or for subsetting
condition <- paste0(x[1:2], collapse = "") == apply(df1[,c('Row','Column')], 1, function(y) {
paste0(y,collapse = "")
})
##Return a column if it meets the condition (first 2 rows are matched in df1)
if(sum(condition) != 0) {
tempdf <- data.frame(x)
names(tempdf) <- df1[condition,]$Site[1]
tempdf
} else {
##If they are not matched, then return an empty column
data.frame(rep(NA,nrow(df2)))
}
}))))
It is quite a condensed piece of code, so I hope the following explanation will help clarify some things:
This basically goes through every column in df2 (with apply(df2, 2, FUN)) and checks if its first 2 rows can be found in the 2nd and 3rd elements of every row in df1. If the condition is met, then it returns that column in a data.frame format with its column name being the value of Site in the matching row in df1; otherwise an empty column (with NA's) is returned. These columns are then bound together with do.call and cbind, and then coerced into a data.frame. Finally, we use the Filter function to remove columns whose values are NA's.
All that should give the following:
Site.A Site.B Site.C
1 2 3
5 4 3
40 42 33
13 47 25
23 0 34
2 41 17
10 29 38
43 27 8
31 1 25
31 40 31
34 12 43
43 30 46
46 49 25
45 7 17
2 13 38
28 12 12
16 19 15
39 28 30
41 24 30
10 20 42
11 4 8
33 40 41
34 26 48
2 29 13
38 0 27
38 34 13
30 29 28
47 2 49
22 10 49
45 37 30
29 31 4
25 24 31
I hope this helps.

Resources