This question already has answers here:
Transposing a dataframe maintaining the first column as heading
(5 answers)
Transposition of a Tibble Using Pivot_Longer() and Pivot_Wider (Tidyverse) [duplicate]
(1 answer)
Closed 1 year ago.
I have the below tibble.
A tibble: 2 x 6
Trial_Type CT_tib_all CT_lum_all CT_tho_all CT_gps_all CT_vest_all
* <fct> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Pre 0.244 0.209 0.309 0.315 0.310
2 Post 0.254 0.211 0.302 0.313 0.316
I would like to flip the rows and columns so I end up with a 6 x 2 tibble, but I'm not sure of the easiest way to do this. How do I get the column variable names to become row labels and the row labels as column variables (Pre and Post)?
You can use pivot_longer and pivot_wider -
library(dplyr)
library(tidyr)
df %>%
pivot_longer(cols = -Trial_Type) %>%
pivot_wider(names_from = Trial_Type, values_from = value)
# name Pre Post
# <chr> <dbl> <dbl>
#1 CT_tib_all 0.244 0.254
#2 CT_lum_all 0.209 0.211
#3 CT_tho_all 0.309 0.302
#4 CT_gps_all 0.315 0.313
#5 CT_vest_all 0.31 0.316
In data.table -
library(data.table)
dcast(melt(setDT(df), id.vars = 'Trial_Type'),
variable~Trial_Type, vvalue.var = 'value')
t i.e. transpose function in baseR may also be used, in combination with tibble::rownames_to_column and tibble::column_to_rownames
library(tibble)
library(dplyr)
df <- read.table(text = 'Trial_Type CT_tib_all CT_lum_all CT_tho_all CT_gps_all CT_vest_all
Pre 0.244 0.209 0.309 0.315 0.310
Post 0.254 0.211 0.302 0.313 0.316', header = T)
df %>% tibble::column_to_rownames('Trial_Type') %>%
t() %>% as.data.frame() %>%
rownames_to_column('Trial_Type')
#> Trial_Type Pre Post
#> 1 CT_tib_all 0.244 0.254
#> 2 CT_lum_all 0.209 0.211
#> 3 CT_tho_all 0.309 0.302
#> 4 CT_gps_all 0.315 0.313
#> 5 CT_vest_all 0.310 0.316
Created on 2021-05-28 by the reprex package (v2.0.0)
We can use transpose from data.table
data.table::transpose(df, make.names = 'Trial_Type', keep.names = 'name')
# name Pre Post
#1 CT_tib_all 0.244 0.254
#2 CT_lum_all 0.209 0.211
#3 CT_tho_all 0.309 0.302
#4 CT_gps_all 0.315 0.313#
5 CT_vest_all 0.310 0.316
A base R option using reshape
reshape(
cbind(name = df$Trial_Type, stack(df[-1])),
direction = "wide",
idvar = "ind",
timevar = "name"
)
gives
ind values.Pre values.Post
1 CT_tib_all 0.244 0.254
3 CT_lum_all 0.209 0.211
5 CT_tho_all 0.309 0.302
7 CT_gps_all 0.315 0.313
9 CT_vest_all 0.310 0.316
Related
I have a database which looks like this but with much more rows and columns.
Several variables (x,y,z) measured at different time (1,2,3).
df <-
tibble(
x1 = rnorm(10),
x2 = rnorm(10),
x3 = rnorm(10),
y1 = rnorm(10),
y2 = rnorm(10),
y3 = rnorm(10),
z1 = rnorm(10),
z2 = rnorm(10),
z3 = rnorm(10),
)
I am trying to create dummies variables from the variables with the same suffix (measured at the same time) like this:
df <- df %>%
mutate(var1= ifelse(x1>0 & (y1<0.5 |z1<0.5),0,1)) %>%
mutate(var2= ifelse(x2>0 & (y2<0.5 |z2<0.5),0,1)) %>%
mutate(var3= ifelse(x3>0 & (y1<0.5 |z3<0.5),0,1))
I am used to coding in SAS or Stata, so I would like to use a function or a loop because I have many more variables in my database.
But I think I don't have the right approach in R to deal with this.
Thank you very much for your help !
{dplyover} makes this kind of operation easy (disclaimer: I'm the maintainer), given that your desired output contains a typo:
I think you want to use all variables with the same digit (1, 2, 3 and so on) in each calculation:
df <- df %>%
mutate(var1= ifelse(x1>0 & (y1<0.5 |z1<0.5),0,1)) %>%
mutate(var2= ifelse(x2>0 & (y2<0.5 |z2<0.5),0,1)) %>%
mutate(var3= ifelse(x3>0 & (y3<0.5 |z3<0.5),0,1))
If that is the case we can use dplyover::over to apply the same function over a vector. Here we construct the vector with extract_names("[0-9]{1}$") which gets us all ending numbers of our variable names here: c(1,2,3). We can then construct the variable names using a special syntax: .("x{.x}"). Here .x evaluates to the first number in our vector so it would return the object name x1 (not a string!) which we can use inside the function argument of over.
library(dplyr)
library(dplyover) # Only on GitHub: https://github.com/TimTeaFan/dplyover
df %>%
mutate(over(cut_names("^[a-z]{1}"),
~ ifelse(.("x{.x}") > 0 & (.("y{.x}") < 0.5 | .("z{.x}") < 0.5), 0, 1),
.names = "var{x}"
))
#> # A tibble: 10 x 12
#> x1 x2 x3 y1 y2 y3 z1 z2 z3 var1
#> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 0.690 0.550 0.911 0.203 -0.111 0.530 -2.09 0.189 0.147 0
#> 2 -0.238 1.32 -0.145 0.744 1.05 -0.448 2.05 -1.04 1.50 1
#> 3 0.888 0.898 -1.46 -1.87 -1.14 1.59 1.91 -0.155 1.46 0
#> 4 -2.78 -1.34 -0.486 -0.0674 0.246 0.141 0.154 1.08 -0.319 1
#> 5 -1.20 0.835 1.28 -1.32 -0.674 0.115 0.362 1.06 0.515 1
#> 6 0.622 -0.713 0.0525 1.79 -0.427 0.819 -1.53 -0.885 0.00237 0
#> 7 -2.54 0.0197 0.942 0.230 -1.37 -1.02 -1.55 -0.721 -1.06 1
#> 8 -0.434 1.97 -0.274 0.848 -0.482 -0.422 0.197 0.497 -0.600 1
#> 9 -0.316 -0.219 0.467 -1.97 -0.718 -0.442 -1.39 -0.877 1.52 1
#> 10 -1.03 0.226 2.04 0.432 -1.02 -0.535 0.954 -1.11 0.804 1
#> # ... with 2 more variables: var2 <dbl>, var3 <dbl>
Alternatively we can use dplyr::across and use cur_column(), get() and gsub() to alter the name of the column on the fly. To name the new variables correctly we use gsub() in the .names argument of across and wrap it in curly braces {} to evaluate the expression.
library(dplyr)
df %>%
mutate(across(starts_with("x"),
~ {
cur_c <- dplyr::cur_column()
ifelse(.x > 0 & (get(gsub("x","y", cur_c)) < 0.5 | get(gsub("x","z", cur_c)) < 0.5), 0, 1)
},
.names = '{gsub("x", "var", .col)}'
))
#> # A tibble: 10 x 12
#> x1 x2 x3 y1 y2 y3 z1 z2 z3 var1
#> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 -0.423 -1.42 -1.15 -1.54 1.92 -0.511 -0.739 0.501 0.451 1
#> 2 -0.358 0.164 0.971 -1.61 1.96 -0.675 -0.0188 -1.88 1.63 1
#> 3 -0.453 -0.758 -0.258 -0.449 -0.795 -0.362 -1.81 -0.780 -1.90 1
#> 4 0.855 0.335 -1.36 0.796 -0.674 -1.37 -1.42 -1.03 -0.560 0
#> 5 0.436 -0.0487 -0.639 0.352 -0.325 -0.893 -0.746 0.0548 -0.394 0
#> 6 -0.228 -0.240 -0.854 -0.197 0.884 0.118 -0.0713 1.09 -0.0289 1
#> 7 -0.949 -0.231 0.428 0.290 -0.803 2.15 -1.11 -0.202 -1.21 1
#> 8 1.88 -0.0980 -2.60 -1.86 -0.0258 -0.965 -1.52 -0.539 0.108 0
#> 9 0.221 1.58 -1.46 -0.806 0.749 0.506 1.09 0.523 1.86 0
#> 10 0.0238 -0.389 -0.474 0.512 -0.448 0.178 0.529 1.56 -1.12 1
#> # ... with 2 more variables: var2 <dbl>, var3 <dbl>
Created on 2022-06-08 by the reprex package (v2.0.1)
You could restructure your data along the principles of tidy data (see e.g. https://cran.r-project.org/web/packages/tidyr/vignettes/tidy-data.html).
Here to a long format and using tidyverse:
library(tidyverse)
df <-
df |>
pivot_longer(everything()) |>
separate(name, c("var", "time"), sep = "(?=[0-9])") |>
pivot_wider(id_col = "time",
names_from = "var",
names_prefix = "var_",
values_from = "value",
values_fn = list) |>
unnest(-time) |>
mutate(new_var = ifelse(var_x > 0 & (var_y < 0.5 | var_z < 0.5), 0, 1))
df
You would probably want to keep the data in a long format, but if you want, you can pivot_wider and get back to the format you started with. E.g.
df |>
pivot_wider(values_from = c(starts_with("var_"), "new_var"),
names_from = "time",
values_fn = list) |>
unnest(everything())
As you suggested, a solution using a loop is definitely possible.
# times as unique non-alphabetical parts of column names
times <- unique(gsub('[[:alpha:]]', '', names(df)))
for (time in times) {
# column names for current time
xyz <- paste0(c('x', 'y', 'z'), time)
df[[paste0('var', time)]] <-
ifelse(df[[xyz[1]]]>0 & (df[[xyz[2]]]<.5 | df[[xyz[3]]]<.5), 0, 1)
}
Another way I can think of is transforming the data into a 3D array (observartion × variable × time) so that you can actually do the computation for all variables at once.
times <- unique(gsub('[[:alpha:]]', '', names(df)))
df.arr <- sapply(c('x', 'y', 'z'),
function(var) as.matrix(df[, paste0(var, times)]),
simplify='array')
new.vars <- ifelse(df.arr[, , 1]>0 & (df.arr[, , 2]<0.5 | df.arr[, , 3]<0.5), 0, 1)
colnames(new.vars) <- paste0('var', times)
cbind(df, new.vars)
Here, sapply creates a matrix from columns of measurings for each variable at different times and stacks them into a 3D array.
If you trust (or ensure) correct ordering of columns in the data frame, instead of using sapply you can create the array just by modifying the object's dimensions. I didn't do any benchmarking but i guess this could be the most computationally efficient solution (if it should matter).
df.arr <- as.matrix(df)
dim(df.arr) <- c(dim(df.arr) / c(1, 3), 3)
I'd like to call a function several times with different variables, each time setting a value to a new variable in the data frame. Here is my failed attempt. I appreciate any help!
dat <- tibble(score1 = runif(10), score2 = score1 * 2)
call_mutate_with_vars <- function(df, var1, var2, var3) {
df <-
df %>%
mutate({{var3}} := ifelse({{var1}} >= {{var2}},0,{{var2}} - {{var1}}))
df
}
call_mutate_with_vars(dat,"score1","score2","newscore")
I receive this error:
Error: Problem with `mutate()` column `newscore`.
i `newscore = ifelse("score1" >= "score2", 0, "score2" - "score1")`.
x non-numeric argument to binary operator
Run `rlang::last_error()` to see where the error occurred.
The embracing operator {{ is meant for variables passed as symbols (i.e., fx(var), not fx("var")). If you need to pass your variables as characters, you can instead use the .data pronoun.
So you can either pass symbols to your current function:
library(dplyr)
set.seed(1)
call_mutate_with_vars <- function(df, var1, var2, var3) {
df %>%
mutate(
{{var3}} := ifelse(
{{var1}} >= {{var2}},
0,
{{var2}} - {{var1}}
)
)
}
call_mutate_with_vars(dat, score1, score2, newscore)
#> # A tibble: 10 x 3
#> score1 score2 newscore
#> <dbl> <dbl> <dbl>
#> 1 0.266 0.531 0.266
#> 2 0.372 0.744 0.372
#> 3 0.573 1.15 0.573
#> 4 0.908 1.82 0.908
#> 5 0.202 0.403 0.202
#> 6 0.898 1.80 0.898
#> 7 0.945 1.89 0.945
#> 8 0.661 1.32 0.661
#> 9 0.629 1.26 0.629
#> 10 0.0618 0.124 0.0618
Or rewrite the function to handle characters:
call_mutate_with_chr_vars <- function(df, var1, var2, var3) {
df %>%
mutate(
!!var3 := ifelse( # note use of !! unquote operator
.data[[var1]] >= .data[[var2]], # to use character as name
0,
.data[[var2]] - .data[[var1]]
)
)
}
call_mutate_with_chr_vars(dat, "score1", "score2", "newscore")
#> # A tibble: 10 x 3
#> score1 score2 newscore
#> <dbl> <dbl> <dbl>
#> 1 0.266 0.531 0.266
#> 2 0.372 0.744 0.372
#> 3 0.573 1.15 0.573
#> 4 0.908 1.82 0.908
#> 5 0.202 0.403 0.202
#> 6 0.898 1.80 0.898
#> 7 0.945 1.89 0.945
#> 8 0.661 1.32 0.661
#> 9 0.629 1.26 0.629
#> 10 0.0618 0.124 0.0618
Created on 2022-03-07 by the reprex package (v2.0.1)
The "Programming with dplyr" vignette is a nice reference for these sorts of problems.
This question already has answers here:
tidyverse pivot_longer several sets of columns, but avoid intermediate mutate_wider steps [duplicate]
(3 answers)
Closed 1 year ago.
Suppose I have a list of dataframes, mylist and I want to do the same operation to each dataframes.
Say my dataframes look like this:
set.seed(1)
test.tbl <- tibble(
case1_diff = rnorm(10,0),
case1_avg = rnorm(10,0),
case2_diff = rnorm(10,0),
case2_avg = rnorm(10,0),
case3_diff = rnorm(10,0),
case3_avg = rnorm(10,0),
case4_diff = rnorm(10,0),
case4_avg = rnorm(10,0),
)
> head(test.tbl)
# A tibble: 6 x 8
case1_diff case1_avg case2_diff case2_avg case3_diff case3_avg case4_diff case4_avg
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 -0.626 1.51 0.919 1.36 -0.165 0.398 2.40 0.476
2 0.184 0.390 0.782 -0.103 -0.253 -0.612 -0.0392 -0.710
3 -0.836 -0.621 0.0746 0.388 0.697 0.341 0.690 0.611
4 1.60 -2.21 -1.99 -0.0538 0.557 -1.13 0.0280 -0.934
5 0.330 1.12 0.620 -1.38 -0.689 1.43 -0.743 -1.25
6 -0.820 -0.0449 -0.0561 -0.415 -0.707 1.98 0.189 0.291
and I wish to stack them into two columns of diff and avg as 40 x 2 dataframe.
Normally, I would just separate it into two objects through select(ends_with("diff")) and select(ends_with("avg")), pivot them, then bind_rows.
However, since my original object is list, I want to do it using map like:
mylist %>%
map(*insertfunction1*) %>%
map(*insertfunction2*)
meaning I would need to do this without separating. I would also need to make sure that diff and avg is correctly paired.
What I have tried so far is
test.tbl %>%
pivot_longer(cols=everything(),
names_to = "metric") %>%
mutate(metric = str_remove(metric,"[0-9]+")) %>%
pivot_wider(id_cols=metric,
values_from=value)
We don't need both pivot_longer and pivot_wider. it can be done within pivot_longer itself by specifying the names_to and the names_sep argument
library(dplyr)
library(tidyr)
test.tbl %>%
pivot_longer(cols = everything(), names_to = c('grp', '.value'),
names_sep = "_") %>%
select(-grp)
-output
# A tibble: 40 x 2
# diff avg
# <dbl> <dbl>
# 1 -0.626 1.51
# 2 0.919 1.36
# 3 -0.165 0.398
# 4 2.40 0.476
# 5 0.184 0.390
# 6 0.782 -0.103
# 7 -0.253 -0.612
# 8 -0.0392 -0.710
# 9 -0.836 -0.621
#10 0.0746 0.388
# … with 30 more rows
I am trying to convert my data frame from wide to long form based on a column's character string. In the example below, I want O2_222.coefficients.x1 and O2_217.coefficients.x1 in a single column, O2_222.R-squared and O2_217.R-squared in a single column and RunTime as it's own. Attempted using melt in the reshape2 package but can't seem to get the syntax right.
structure(list(O2_222.coefficients.x1 = c(0.494206524044508, 0.351865091962266,
0.348933739038027, 0.412232161883577, 0.702783684327072), `O2_222.R-squared` =
c(0.922054236839182, 0.915753625911676, 0.91109476704698, 0.917998834313392,
0.967759465780247), O2_217.coefficients.x1 = c(0.390012278483346, 0.0694948285748309,
0.0323121611694059, 0.0372526286990146, 0.194291648564898), `O2_217.R-squared` =
c(0.921256057864199, 0.537913087580067, 0.271398305115866, 0.274339042666519,
0.908338928665188), RunTime = c(9.03, 14.08, 19.08, 24.08, 29.08)), row.names = c(116L,
216L, 316L, 416L, 516L), class = "data.frame")
We could use pivot_longer from tidyr and specify the names_sep as .
library(tidyr)
library(dplyr)
df1 %>%
pivot_longer(cols = -RunTime, names_to = c('group', '.value'), names_sep="\\.")
# A tibble: 10 x 4
# RunTime group coefficients `R-squared`
# <dbl> <chr> <dbl> <dbl>
# 1 9.03 O2_222 0.494 0.922
# 2 9.03 O2_217 0.390 0.921
# 3 14.1 O2_222 0.352 0.916
# 4 14.1 O2_217 0.0695 0.538
# 5 19.1 O2_222 0.349 0.911
# 6 19.1 O2_217 0.0323 0.271
# 7 24.1 O2_222 0.412 0.918
# 8 24.1 O2_217 0.0373 0.274
# 9 29.1 O2_222 0.703 0.968
#10 29.1 O2_217 0.194 0.908
I have a two-part problem. I've searched all over stack and found answers related to my problems, but no variations I've tried have worked yet. Thanks in advance for any help!
I have a large data frame that contains many variables.
First, I want to (1) standardize a variable by another variable (in my case, speaker), and (2) filter out values after the variable has been standardized (greater than 2 standard deviations away from the mean). (1) and (2) can be taken care of by a function using dplyr.
Second, I have many variables I want to do this for, so I'm trying to find an automated way to do this, such as with a for loop.
Problem 1: Writing a function containing dplyr functions
Here is a sample of what my data frame looks like:
df = data.frame(speaker=c("eng1","eng1","eng1","eng1","eng1","eng1","eng2","eng2","eng2","eng2","eng2"),
ratio_means001=c(0.56,0.202,0.695,0.436,0.342,10.1,0.257,0.123,0.432,0.496,0.832),
ratio_means002=c(0.66,0.203,0.943,0.432,0.345,0.439,0.154,0.234,NA,0.932,0.854))
Output:
speaker ratio_means001 ratio_means002
1 eng1 0.560 0.660
2 eng1 0.202 0.203
3 eng1 0.695 0.943
4 eng1 0.436 0.432
5 eng1 0.342 0.345
6 eng1 10.100 0.439
7 eng2 0.257 0.154
8 eng2 0.123 0.234
9 eng2 0.432 NA
10 eng2 0.496 0.932
11 eng2 0.832 0.854
Below is the basic code I want to turn into a function:
standardized_data = group_by(df, speaker) %>%
mutate(zRatio1 = as.numeric(scale(ratio_means001)))%>%
filter(!abs(zRatio1) > 2)
So that the data frame will now look like this (for example):
speaker ratio_means001 ratio_means002 zRatio1
(fctr) (dbl) (dbl) (dbl)
1 eng1 0.560 0.660 -0.3792191
2 eng1 0.202 0.203 -0.4699781
3 eng1 0.695 0.943 -0.3449943
4 eng1 0.436 0.432 -0.4106552
5 eng1 0.342 0.345 -0.4344858
6 eng2 0.257 0.154 -0.6349445
7 eng2 0.123 0.234 -1.1325034
8 eng2 0.432 NA 0.0148525
9 eng2 0.496 0.932 0.2524926
10 eng2 0.832 0.854 1.5001028
Here is what I have in terms of a function so far. The mutate part works, but I've been struggling with adding the filter part:
library(lazyeval)
standardize_variable = function(col1, new_col_name) {
mutate_call = lazyeval::interp(b = interp(~ scale(a)), a = as.name(col1))
group_by(data,speaker) %>%
mutate_(.dots = setNames(list(mutate_call), new_col_name)) %>%
filter_(interp(~ !abs(b) > 2.5, b = as.name(new_col_name))) # this part does not work
}
I receive the following error when I try to run the function:
data = standardize_variable("ratio_means001","zRatio1")
Error in substitute_(`_obj`[[2]], values) :
argument "_obj" is missing, with no default
Problem 2: Looping over the function
There are many variables that I'd like to apply the above function to, so I would like to find a way to either use a loop or another helpful function to help automate this process. The variable names differ only in a number at the end, so I have come up with something like this:
d <- data.frame()
for(i in 1:2)
{
col1 <- paste("ratio_means00", i, sep = "")
new_col <- paste("zRatio", i, sep = "")
d <- rbind(d, standardize_variable(col1, new_col))
}
However, I get the following error:
Error in match.names(clabs, names(xi)) :
names do not match previous names
Thanks again for any help on these issues!
Alternative 1
I believe the main problem you were having with your function had to do with you calling interp twice. Fixing that led to an additional problem with filter, which I think was due to scale adding attributes (I'm using a development version dplyr, dplyr_0.4.3.9001). Wrapping as.numeric around scale gets rid of that.
So with the fixes your function looks like:
standardize_variable = function(col1, new_col_name) {
mutate_call = lazyeval::interp(~as.numeric(scale(a)), a = as.name(col1))
group_by(df, speaker) %>%
mutate_(.dots = setNames(list(mutate_call), new_col_name)) %>%
filter_(interp(~ !abs(b) > 2, b = as.name(new_col_name)))
}
I found the loop through the variables to be a bit more complicated than what you had, as I believe you want to merge your datasets back together once you make one for each variable. One option is to save them to a list and then use do.call with merge to get the final dataset.
d = list()
for(i in 1:2) {
col1 <- paste("ratio_means00", i, sep = "")
new_col <- paste("zRatio", i, sep = "")
d[[i]] = standardize_variable(col1, new_col)
}
do.call(merge, d)
speaker ratio_means001 ratio_means002 zRatio1 zRatio2
1 eng1 0.202 0.203 -0.4699781 -1.1490444
2 eng1 0.342 0.345 -0.4344858 -0.6063693
3 eng1 0.436 0.432 -0.4106552 -0.2738853
4 eng1 0.560 0.660 -0.3792191 0.5974521
5 eng1 0.695 0.943 -0.3449943 1.6789806
6 eng2 0.123 0.234 -1.1325034 -0.7620572
7 eng2 0.257 0.154 -0.6349445 -0.9590348
8 eng2 0.496 0.932 0.2524926 0.9565726
9 eng2 0.832 0.854 1.5001028 0.7645194
Alternative 2
An alternative to all of this would be to use mutate_each and rename_ for the first part of the problem and then use an interp with a lapply loop for the final filtering of all of the scaled variables simultaneously.
In the code below I take advantage of the fact that mutate_each allows naming for single functions starting in dplyr_0.4.3.9001. Things look a bit complicated in rename_ because I was making the names you wanted for the new columns. To simplify things you could leave them ending in _z from mutate_each and save yourself the complicated step of rename_ with gsub and grepl.
df2 = df %>%
group_by(speaker) %>%
mutate_each(funs(z = as.numeric(scale(.))), starts_with("ratio_means00")) %>%
rename_(.dots = setNames(names(.)[grepl("z", names(.))],
paste0("zR", gsub("r|_z|_means00", "", names(.)[grepl("z", names(.))]))))
Once that's done, you just need to filter by multiple columns. I think it's easiest to make a list of conditions you want to filter with use interp and lapply, and then give that to the .dots argument of filter_.
dots = lapply(names(df2)[starts_with("z", vars = names(df2))],
function(y) interp(~abs(x) < 2, x = as.name(y)))
filter_(df2, .dots = dots)
Source: local data frame [9 x 5]
Groups: speaker [2]
speaker ratio_means001 ratio_means002 zRatio1 zRatio2
(fctr) (dbl) (dbl) (dbl) (dbl)
1 eng1 0.560 0.660 -0.3792191 0.5974521
2 eng1 0.202 0.203 -0.4699781 -1.1490444
3 eng1 0.695 0.943 -0.3449943 1.6789806
4 eng1 0.436 0.432 -0.4106552 -0.2738853
5 eng1 0.342 0.345 -0.4344858 -0.6063693
6 eng2 0.257 0.154 -0.6349445 -0.9590348
7 eng2 0.123 0.234 -1.1325034 -0.7620572
8 eng2 0.496 0.932 0.2524926 0.9565726
9 eng2 0.832 0.854 1.5001028 0.7645194
Alternative 3
I often find these problems most straightforward if I reshape the dataset instead of working across columns. For example, still using the newest version of mutate_each but skipping the renaming step for simplicity you could gather all the standardized columns together using the gather function from tidyr and then filter the new column.
library(tidyr)
df %>%
group_by(speaker) %>%
mutate_each(funs(z = as.numeric(scale(.))), starts_with("ratio_means00")) %>%
gather(group, zval, ends_with("_z")) %>%
filter(abs(zval) <2 )
# First 12 lines of output
Source: local data frame [20 x 5]
Groups: speaker [2]
speaker ratio_means001 ratio_means002 group zval
<fctr> <dbl> <dbl> <chr> <dbl>
1 eng1 0.560 0.660 ratio_means001_z -0.3792191
2 eng1 0.202 0.203 ratio_means001_z -0.4699781
3 eng1 0.695 0.943 ratio_means001_z -0.3449943
4 eng1 0.436 0.432 ratio_means001_z -0.4106552
5 eng1 0.342 0.345 ratio_means001_z -0.4344858
6 eng2 0.257 0.154 ratio_means001_z -0.6349445
7 eng2 0.123 0.234 ratio_means001_z -1.1325034
8 eng2 0.432 NA ratio_means001_z 0.0148525
9 eng2 0.496 0.932 ratio_means001_z 0.2524926
10 eng2 0.832 0.854 ratio_means001_z 1.5001028
11 eng1 0.560 0.660 ratio_means002_z 0.5974521
12 eng1 0.202 0.203 ratio_means002_z -1.1490444
...
If the desired final form is the wide format, you can use spread (also from tidyr for that. One advantage (to me) is that you can keep all values of one variable even when another variable failed the filtering step.
df %>%
group_by(speaker) %>%
mutate_each(funs(z = as.numeric(scale(.))), starts_with("ratio_means00")) %>%
gather(group, zval, ends_with("_z")) %>%
filter(abs(zval) <2 ) %>%
spread(group, zval)
Source: local data frame [11 x 5]
Groups: speaker [2]
speaker ratio_means001 ratio_means002 ratio_means001_z ratio_means002_z
<fctr> <dbl> <dbl> <dbl> <dbl>
1 eng1 0.202 0.203 -0.4699781 -1.1490444
2 eng1 0.342 0.345 -0.4344858 -0.6063693
3 eng1 0.436 0.432 -0.4106552 -0.2738853
4 eng1 0.560 0.660 -0.3792191 0.5974521
5 eng1 0.695 0.943 -0.3449943 1.6789806
6 eng1 10.100 0.439 NA -0.2471337
7 eng2 0.123 0.234 -1.1325034 -0.7620572
8 eng2 0.257 0.154 -0.6349445 -0.9590348
9 eng2 0.432 NA 0.0148525 NA
10 eng2 0.496 0.932 0.2524926 0.9565726
11 eng2 0.832 0.854 1.5001028 0.7645194
If you don't want to keep the NA, you can always na.omit them at a later time.