In R, how can I set the names of an object and return it in one line? - r

I would like to set the names of my R object and return it in one line. It should look something like:
names(doWork(), c("a", "b", "c"))
And perform the equivalent of:
x <- doWork()
names(x) <- c("a", "b", "c")
x
Is this possible?

You can try setNames
x <- setNames(doWork(), letters[1:3])

To add to what #rawr states:
`names<-`(x, letters[1:3])
works. This isn't super interesting for setting names, since setNames exists, but there are many other attribute replacement functions that don't have a corresponding attribute setting function, so this can become useful (when playing code golf). For example, if we want to set column names for a list of matrices:
mats <- replicate(2, matrix(sample(1:100, 4), 2), simplify=F) # list of matrices
lapply(mats, `colnames<-`, LETTERS[1:2])
Produces:
[[1]]
A B
[1,] 78 59
[2,] 39 93
[[2]]
A B
[1,] 99 54
[2,] 1 16

Related

Assigning complex values to character elements of data frame in R

There are three columns in my data frame which are characters, "A","B", and "C" (this order can vary for different data frames). I want to assign values to them, A= 1+0i, B=2+3i and C=3+2i. I use as.complex(factor(col1)) and the same thing for column two and three, but it makes all three column equal to 1+0i!!
col1 <- c("A","A", "A")
col2 <- c("B", "B","B")
col3 <- c("C","C","C")
df <- data.frame(col1,col2,col3)
print(df)
A= 1+0i
B=2+3i
C=3+2i
df2<- transform(df, col1=as.complex(as.factor(col1)),col2=as.complex(as.factor(col2)),col3=as.complex(as.factor(col3)))
sapply(df2,class)
View(df2)
So this is a weird thing you're doing. You have a column of strings, letters like "A" and "B". Then you have objects with the same names, A = 1 + 0i, etc. Normally we don't treat object names as "data", but you're sort of mixing the two here. The solution I'd propose is to make everything data: combine your A, B, and C values into a vector, and give the vector names accordingly. Then we can replace the values in the data frame with the corresponding values from our named vector:
vec = c(A, B, C)
names(vec) = c("A", "B", "C")
df[] = lapply(df, \(x) vec[x])
df
# col1 col2 col3
# 1 1+0i 2+3i 3+2i
# 2 1+0i 2+3i 3+2i
# 3 1+0i 2+3i 3+2i

Is there a R function for limiting the length of list elements?

I am struggling with a list manipulation in R right now. I have a list containing about 3000 elements, where each element is a character vector. The length of these character vectors is between 7 and 10.
I would like to manipulate this list in such a way, that those character vectors, that contain more than 7 elements, are limited to only the first 7 elements - hence drop the 8th, 9th, and 10th element/word/number of the respective character vector of the list.
Is there an easy way to do this? I hope you understand what I mean.
Thanks in advance!
You can use lapply as below:
mylist <- list(a = c("a", "b"),
b = c("a", "b", "c"))
mylist
$a
[1] "a" "b"
$b
[1] "a" "b" "c"
mylist2 <- lapply(mylist, function(x) {
x[1:min(length(x), 2)]
})
mylist2
$a
[1] "a" "b"
$b
[1] "a" "b"
What you need is an auxiliary function that will shorten your vector. Something like
shorten_vector <- function(y, max_length = 7){
# NOTE: assumes that there are at least 7 elements in the vector.
y[seq_len(max_length)]
}
you can then shorten the vectors in your list with
lapply(your_list, shorten_vector)
Or better
lapply(your_list, head, 7) # Thanks Moody
Reproducible example
# Make an object for an example. A list of length 15
# where each element is a character vector between length 7 and 10
random_length <- sample(7:10, 15, replace = TRUE)
char_list <-
lapply(random_length,
function(x){
letters[seq_len(x)]
})
# utility function
shorten_vector <- function(y, max_length = 7){
y[seq_len(max_length)]
}
lapply(char_list,
shorten_vector)
Bonus
You said in a comment on Sonny's answer that you weren't really sure how the lapply worked. At it's conceptual core, lapply is a wrapper around a for loop. The equivalent for loop would be
for(i in seq_along(char_list)){
char_list[[i]] <- shorten_vector(char_list[[i]])
}
char_list
The lapply just handles the iteration limits for you and looks a little cleaner on the screen.

using purrr to extract elements from multiple lists starting with a common letter

I have a list of lists. One element in each list has a name beginning with "n_". How do I extract these elements and store them in a separate list? Can I use a combination of map and starts_with?
E.g.:
m1 <- list(n_age = c(19,40,39),
names = c("a", "b", "c"))
m2 <- list(n_gender = c("m","f","f"),
names = c("f", "t", "d"))
nice_list <- list(m1, m2)
I was hoping that something like the following to work (it doesn't!):
output <- map(nice_list, starts_with("n_"))
You could (ab)use partial matching of $:
map(nice_list, `$`, "n_")
(I don't really recommend it).
(And I can't figure out why lapply(nice_list, `$`, "n_") doesn't work (gives a list(NULL, NULL)).
How about this?
map(nice_list, ~.x[grep("n_", names(.x))])
#[[1]]
#[[1]]$n_age
#[1] 19 40 39
#
#
#[[2]]
#[[2]]$n_gender
#[1] "m" "f" "f"
Or using starts_with
map(nice_list, ~.x[starts_with("n_", vars = names(.x))])
Or to flatten the nested list, you could do
unlist(map(nice_list, ~.x[grep("n_", names(.x))]), recursive = F)
#$n_age
#[1] 19 40 39
#
#$n_gender
#[1] "m" "f" "f"

R - ff package : find the most frequent element in ffdf and delete the rows where is located

I need a suggestion to find the most frequent element in ffdf and after that to delete the rows where is located.
I decided to try the ff package as I'm working with very big data and with base R I am running out of memory.
Here is a little example:
# create a base R Matrix
> z<-matrix(c("a", "b", "a", "c", "b", "b", "c", "c", "b", "a"),nrow=5,ncol=2,byrow = TRUE)
> z
[,1] [,2]
[1,] "a" "b"
[2,] "a" "c"
[3,] "b" "b"
[4,] "c" "c"
[5,] "b" "a"
# convert z to ffdf
> u=as.data.frame(z, stringsAsFactors=TRUE)
> u=as.ffdf(u)
> u
ffdf data
V1 V2
1 a b
2 a c
3 b b
4 c c
5 b a
Im looking for:
Export the most frequent element in ffdf (in this case it is "b")
Delete from ffdf all the rows where "b" is located
So, the new ffdf must be as below:
V1 V2
1 a c
2 c c
In base R I found the way with the "table" function
temp <- table(as.vector(z))
t1<-names(temp)[temp == max(temp)]
z1<- z[rowSums(z== t1[1]) == 0, ]
But working with huge data I need something like the ff package.
require(ff)
z <- matrix(c("a","b","f","c","f","b","e","c","b","e"),nrow=5,ncol=2,byrow = TRUE)
u <- as.data.frame(z, stringsAsFactors=TRUE)
u <- as.ffdf(u)
u
The following should work on any sized dataset. It uses table.ff and ffwhich from ffbase, ffrowapply from ff and indexing based on ff integer vectors.
require(ffbase)
require(plyr)
## Detect most frequent item (assuming the levels of all columns can be different)
columnfreqs <- lapply(colnames(u), FUN=function(column) table(u[[column]]))
columnfreqs <- lapply(columnfreqs, FUN=function(x) as.data.frame(t(as.matrix(x))))
itemfreqs <- colSums(do.call(rbind.fill, columnfreqs), na.rm=TRUE)
mostfrequent <- names(sort(itemfreqs, decreasing = TRUE))[1]
## Identify the lines where the most frequent item occurs in each row of the ffdf
idx <- ffrowapply(
EXPR = apply(u[i1:i2,], MARGIN=1, FUN=function(row) any(row %in% mostfrequent)),
X=u,
RETURN = TRUE, FF_RETURN = TRUE, RETCOL = NULL, VMODE = "logical")
idx <- ffwhich(idx, idx != TRUE) # remove it is in there + convert logicals to integers
## Remove them
u[idx, ]

How to calculate how many times vector appears in a list? in R

I have a list of 10,000 vectors, and each vector might have different elements and different lengths. I would like to know how many unique vectors I have and how often each unique vector appears in the list.
I guess the way to go is the function "unique", but I don't know how I could use it to also get the number of times each vector is repeated.
So what I would like to get is something like that:
"a" "b" "c" d" 301
"a" 277
"b" c" 49
being the letters, the contents of each unique vector, and the numbers, how often are repeated.
I would really appreciate any possible help on this.
thank you very much in advance.
Tina.
Maybe you should look at table:
Some sample data:
myList <- list(A = c("A", "B"),
B = c("A", "B"),
C = c("B", "A"),
D = c("A", "B", "B", "C"),
E = c("A", "B", "B", "C"),
F = c("A", "C", "B", "B"))
Paste your vectors together and tabulate them.
table(sapply(myList, paste, collapse = ","))
#
# A,B A,B,B,C A,C,B,B B,A
# 2 2 1 1
You don't specify whether order matters (that is, is A, B the same as B, A). If it does, you can try something like:
table(sapply(myList, function(x) paste(sort(x), collapse = ",")))
#
# A,B A,B,B,C
# 3 3
Wrap this in data.frame for a vertical output instead of horizontal, which might be easier to read.
Also, do be sure to read How to make a great R reproducible example? as already suggested to you.
As it is, I'm just guessing at what you're trying to do.

Resources