summarise vs. summarise_each function in dplyr package - r

I am trying to summarise the value for one variable after splitting the data with group_by using dplyr package, the following code works fine and the output is listed below, but I can not substitute summarise_each with summriase even only one column need to be calculated, I wonder why?
iris %>% group_by(Species) %>% select(one_of('Sepal.Length')) %>%
summarise_each(funs(mean(.)))
or I will get the output like "S3:lazy".

summarize and summarize_each work quite differently. summarize is in fact simpler — just specify the expression directly:
iris %>%
group_by(Species) %>%
select(Sepal.Length) %>%
summarize(Sepal.Length = mean(Sepal.Length))
You can choose any name for the output column, it doesn’t need to be the same as the input.

Related

Filter the first group after group_by

Sometimes it is handy to take a test case out of your data when working with group_by() from the dplyr library. I was wondering if there is any fast way to just grab the first group of a grouped dataframe and cast it to a new dataframe.
All I could come up with was this workaround:
library(dplyr)
smalldf <- mtcars %>% group_by(gear) %>% group_split(.) %>% .[[1]]

Using the R syntax sequence operator ":" within the the sum command with more then 50 columns

i would like to index by column name within the sum command using the sequence operator.
library(dbplyr)
library(tidyverse)
df=data.frame(
X=c("A","B","C"),
X.1=c(1,2,3),X.2=c(1,2,3),X.3=c(1,2,3),X.4=c(1,2,3),X.5=c(1,2,3),X.6=c(1,2,3),X.7=c(1,2,3),X.8=c(1,2,3),X.9=c(1,2,3),X.10=c(1,2,3),
X.11=c(1,2,3),X.12=c(1,2,3),X.13=c(1,2,3),X.14=c(1,2,3),X.15=c(1,2,3),X.16=c(1,2,3),X.17=c(1,2,3),X.18=c(1,2,3),X.19=c(1,2,3),X.20=c(1,2,3),
X.21=c(1,2,3),X.22=c(1,2,3),X.23=c(1,2,3),X.24=c(1,2,3),X.25=c(1,2,3),X.26=c(1,2,3),X.27=c(1,2,3),X.28=c(1,2,3),X.29=c(1,2,3),X.30=c(1,2,3),
X.31=c(1,2,3),X.32=c(1,2,3),X.33=c(1,2,3),X.34=c(1,2,3),X.35=c(1,2,3),X.36=c(1,2,3),X.37=c(1,2,3),X.38=c(1,2,3),X.39=c(1,2,3),X.40=c(1,2,3),
X.41=c(1,2,3),X.42=c(1,2,3),X.43=c(1,2,3),X.44=c(1,2,3),X.45=c(1,2,3),X.46=c(1,2,3),X.47=c(1,2,3),X.48=c(1,2,3),X.49=c(1,2,3),X.50=c(1,2,3),
X.51=c(1,2,3),X.52=c(1,2,3),X.53=c(1,2,3),X.54=c(1,2,3),X.55=c(1,2,3),X.56=c(1,2,3))
Is there a quicker way todo this. The following provides the correct result. However, for large datasets (larger than this one ) it becomes vary laborious to deal with especially when pivot_wider is used and the columns are not created before hand (like above)
df %>% rowwise() %>% mutate(
Result_column=case_when(
X=="A"~ sum(c(X.1,X.2,X.3,X.4,X.5)),
X=="B"~ sum(c(X.4,X.5)),
X=="C" ~ sum(c( X.3, X.4, X.5, X.6, X.7, X.8, X.9, X.10, X.11, X.12, X.13, X.14, X.15, X.16,
X.17, X.18, X.19, X.20, X.21, X.22, X.23, X.24, X.25, X.26, X.27, X.28, X.29, X.30,
X.31, X.32, X.33, X.34, X.35, X.36, X.37, X.38, X.39, X.40, X.41, X.42,X.43, X.44,
X.45, X.46, X.47, X.48, X.49, X.50, X.51, X.52, X.53, X.54, X.55, X.56)))) %>% dplyr::select(Result_column)
The following is the how it would be used when using "select" syntax, which is that i would like to use. However, does not provide correct numerical solution. One can shorter the code by ~50 entries, by using a sequence operator ":".
df %>% rowwise() %>% mutate(
Result_column=case_when(
X=="A"~ sum(c(X.1:X.5)),
X=="B"~ sum(c(X.4:X.5)),
X=="C" ~ sum(c(X.3:X.56)))) %>% dplyr::select(Result_column)
below is a related question, however, not the same because what is needed is not a column that starts with "X" but rather a sequence.
Using mutate rowwise over a subset of columns
EDIT:
the provided code (below) from cnbrowlie is correct.
df %>% mutate(
Result_column=case_when(
X=="A"~ sum(c(X.1:X.5)),
X=="B"~ sum(c(X.4:X.5)),
X=="C" ~ sum(c(X.3:X.56)))) %>% dplyr::select(Result_column)
This can be done with dplyr>=1.0.0 using rowSums() (which computes the sum for a row across multiple columns) and across() (which superceded vars() as a method for specifying columns in a dataframe, allowing the use of : to select sequences of columns):
df %>% rowwise() %>% mutate(
Result_column=case_when(
X=="A"~ rowSums(across(X.1:X.5)),
X=="B"~ rowSums(across(X.4:X.5)),
X=="C" ~ rowSums(across(X.3:X.56))
)
) %>% dplyr::select(Result_column)

dplyr mutate using dynamic variable name while respecting group_by

I'm trying as per
dplyr mutate using variable columns
&
dplyr - mutate: use dynamic variable names
to use dynamic names in mutate. What I am trying to do is to normalize column data by groups subject to a minimum standard deviation. Each column has a different minimum standard deviation
e.g. (I omitted loops & map statements for convenience)
require(dplyr)
require(magrittr)
data(iris)
iris <- tbl_df(iris)
minsd <- c('Sepal.Length' = 0.8)
varname <- 'Sepal.Length'
iris %>% group_by(Species) %>% mutate(!!varname := mean(pluck(iris,varname),na.rm=T)/max(sd(pluck(iris,varname)),minsd[varname]))
I got the dynamic assignment & variable selection to work as suggested by the reference answers. But group_by() is not respected which, for me at least, is the main benefit of using dplyr here
desired answer is given by
iris %>% group_by(Species) %>% mutate(!!varname := mean(Sepal.Length,na.rm=T)/max(sd(Sepal.Length),minsd[varname]))
Is there a way around this?
I actually did not know much about pluck, so I don't know what went wrong, but I would go for this and this works:
iris %>%
group_by(Species) %>%
mutate(
!! varname :=
mean(!!as.name(varname), na.rm = T) /
max(sd(!!as.name(varname)),
minsd[varname])
)
Let me know if this isn't what you were looking for.
The other answer is obviously the best and it also solved a similar problem that I have encountered. For example, with !!as.name(), there is no need to use group_by_() (or group_by_at or arrange_() (or arrange_at()).
However, another way is to replace pluck(iris,varname) in your code with .data[[varname]]. The reason why pluck(iris,varname) does not work is that, I suppose, iris in pluck(iris,varname) is not grouped. However, .data refer to the tibble that executes mutate(), and so is grouped.
An alternative to as.name() is rlang::sym() from the rlang package.

dplyr 0.5: arrange() using groupings

I've got a lot of code written in dplyr 0.4.3, that relied on the grouped arrange() function. As of the 0.5 release, arrange no longer applies grouping.
This decision baffles me, as this makes arrange() inconsistent with other dplyr verbs, and surely a user could just ungroup() before arrange() if ungrouped is required. I would have hoped for perhaps a parameter in arrange() to retain grouped_by behavior, but alas!
I therefore have to rewrite my grouped arrange. At this point, my only option seems to be to break up the pipe at the arrange call, loop through the groups and arrange group by group, and then bind() the result again. I'm hoping there might be a more elegant solution?
Below is an MRE, I'd like to run a cumsum on wt per group_by(cyl). Many thanks for ideas/suggestions.
library(dplyr)
mtcars %>%
group_by(cyl) %>%
arrange(desc(mpg)) %>%
mutate(WtCum = cumsum(wt))
To order within groups in dplyr 0.5, add the grouping variable before the other ordering variables within arrange.
mtcars %>%
group_by(cyl) %>%
arrange(cyl, desc(mpg))
If you want to keep around an “old arrange”, you may use this snippet:
arrange_old <- function(.data, ...) {
dplyr::arrange_(.data, .dots = c(groups(.data), lazyeval::lazy_dots(...)))
}
This will respect grouping by basically prepending the group variables to the new arrange call.
Then you can do:
mtcars %>%
group_by(cyl) %>%
arrange_old(desc(mpg))
For what it's worth, I've also found this change confusing and unintuitive, and I keep making the mistake of forgetting to explicitly specify the grouping.

Take a sample without group in dplyr, R

I know how to take a random sample each group from a dataframe using sample_n or sample_frac in dplyr, which can go like this,
dataset %>%
group_by(user_id) %>%
sample_n(10)
However, I have a slightly different question. I want to take a random sample from the whole dataset. It should be as simple as this one,
sample_n(dataset,10)
But, because I have used group_by command on the dataset in a previous case, it seems the group_by still takes effect here. The second command is equivalent to the first here.
I wonder how can I remove the effect of group_by and get a random sample from the whole dataset?
We can use ungroup() to remove any group variable and then apply the sample_n
dataset %>%
group_by(user_id) %>%
ungroup() %>%
sample_n(10)

Resources