Error in as.environment(pos) : invalid 'pos' argument

I've been working with R for the past week to transfer my VBA code. I worked on a loop with my father to assign a data frame column with values from another data frame column, but I am getting an error back: Error in as.environment(pos) : invalid 'pos' argument. Since my knowledge and experience of R is limited, I do not know if I should be using a different function or how to fix my line of code.

The Q_new$Vol..mL variable contains 517 rows of numbers such as 69, 68, 68, 67, 66, 65, 64, 64, 63, 62, 61,60, 79, 78, 77 .... The Infil_Data.Time.1$m contains 517 rows of no data (a blank cell). What I want to do is take the first number of every 12th row from the Q_new$Vol..mL variable and duplicate it down 12 times in the Infil_Data.Time.1$m variable. So it should look like 69,69,69,69,69,69,69,69,69,69,69,69,79,79,79,79,79,79,79,79,79,79,79,79....

I used the reprex as R Studio Community recommend. Let me know if what I have below is not properly formatted. Or additional information is needed.

jeff <- while (!is.null(Q_new$Vol..mL)) {
    for (x in 1:11) {
        R1 <- R1 + 1 %>% assign(Infil_Data.Time.1$m, Q_new[R2, 
            1]) %>% (next)(x)
    }
    R2 = R2 + 1
}
#> Error in eval(expr, envir, enclos): object 'Q_new' not found

The error message in your title it doesn't seems related to the code you are showing, also a reprex is a self contained chunck of code (including sample data) that can be directly copied and executed elsewhere
You may want to read this

Have in mind that VBA and R have very different sintaxis, so translation is not straight forward.

Do you need to see my data frames then?

You can use datapasta to include a small but representative part of your data in a reprex, see this blog post by mara

Thank you. I really appreciate the help so that my future questions will not lack in quality. So here is part of the Q_new data frame:

tibble::tribble(~Site.ID, ~Vol..mL., "H1", 63L, "H2", 82L, "H3", 
    69L)
#> # A tibble: 3 x 2
#>   Site.ID Vol..mL.
#>   <chr>      <int>
#> 1 H1            63
#> 2 H2            82
#> 3 H3            69

Data frame Infil_Data.Time.1 looks like:

tibble::tribble(~m, ~Time, ~Site.ID, ~Vol..mL., NA, 0L, "H1", 
    63, NA, 30L, "H1", 62, NA, 60L, "H1", 60, NA, 90L, "H1", 
    59, NA, 120L, "H1", 58, NA, 150L, "H1", 56, NA, 180L, "H1", 
    54, NA, 210L, "H1", 52.5, NA, 240L, "H1", 50, NA, 270L, "H1", 
    48.5, NA, 300L, "H1", 46.5, NA, 0L, "H2", 82, NA, 30L, "H2", 
    77, NA, 60L, "H2", 73, NA, 90L, "H2", 68, NA, 120L, "H2", 
    65, NA, 150L, "H2", 61, NA, 180L, "H2", 56, NA, 210L, "H2", 
    52, NA, 240L, "H2", 47.5, NA, 270L, "H2", 42.5, NA, 300L, 
    "H2", 37.5)
#> # A tibble: 22 x 4
#>    m      Time Site.ID Vol..mL.
#>    <lgl> <int> <chr>      <dbl>
#>  1 NA        0 H1          63  
#>  2 NA       30 H1          62  
#>  3 NA       60 H1          60  
#>  4 NA       90 H1          59  
#>  5 NA      120 H1          58  
#>  6 NA      150 H1          56  
#>  7 NA      180 H1          54  
#>  8 NA      210 H1          52.5
#>  9 NA      240 H1          50  
#> 10 NA      270 H1          48.5
#> # ... with 12 more rows

And lastly, I want Infil_Data.Time to look like:

tibble::tribble(~m, ~Time, ~Site.ID, ~Vol..mL., 63L, 0L, "H1", 
    63, 63L, 30L, "H1", 62, 63L, 60L, "H1", 60, 63L, 90L, "H1", 
    59, 63L, 120L, "H1", 58, 63L, 150L, "H1", 56, 63L, 180L, 
    "H1", 54, 63L, 210L, "H1", 52.5, 63L, 240L, "H1", 50, 63L, 
    270L, "H1", 48.5, 63L, 300L, "H1", 46.5, 82L, 0L, "H2", 82, 
    82L, 30L, "H2", 77, 82L, 60L, "H2", 73, 82L, 90L, "H2", 68, 
    82L, 120L, "H2", 65, 82L, 150L, "H2", 61, 82L, 180L, "H2", 
    56, 82L, 210L, "H2", 52, 82L, 240L, "H2", 47.5, 82L, 270L, 
    "H2", 42.5, 82L, 300L, "H2", 37.5)
#> # A tibble: 22 x 4
#>        m  Time Site.ID Vol..mL.
#>    <int> <int> <chr>      <dbl>
#>  1    63     0 H1          63  
#>  2    63    30 H1          62  
#>  3    63    60 H1          60  
#>  4    63    90 H1          59  
#>  5    63   120 H1          58  
#>  6    63   150 H1          56  
#>  7    63   180 H1          54  
#>  8    63   210 H1          52.5
#>  9    63   240 H1          50  
#> 10    63   270 H1          48.5
#> # ... with 12 more rows

The code I wrote should give back the third data frame that I provided.

R1 <- 0
R2 <- 1
jeff <- while (!is.null(Q_new$Vol..mL)) {
    for (x in 1:11) {
        R1 <- R1 + 1 %>% assign(Infil_Data.Time.1$m, Q_new[R2, 
            1]) %>% (next)(x)
    }
    R2 = R2 + 1
}
#> Error in eval(expr, envir, enclos): object 'Q_new' not found

Look at assign() documentation

assign(x, value, pos = -1, envir = as.environment(pos),
       inherits = FALSE, immediate = TRUE)

As you use the function in a pipe, first x is the LHS of %>%, value is Infil_Data.Time.1$m, and pos is Q_new[R2, 1]. it is why you have the error, because it is not a correct pos argument. pos must be

The pos argument can specify the environment in which to assign the object in any of several ways: as -1 (the default), as a positive integer (the position in the search list); as the character string name of an element in the search list; or as an environment (including using sys.frame to access the currently active function calls).

What do you want to do exactly with assign call ?
I would not use that in a regular pipe with %>%, and inside a for-loop.
If you can explain what you want to achieve, we can help further.

1 Like

What I am trying to achieve is to take the first Vol..mL value that corresponds to Time = 0 in Data.Time.1 and repeat it 12 times in a new variable called "m". Then take the next Vol..mL value that corresponds to Time = 0 and repeat it 12 times. I want to continue this through the whole data frame until there are no more Time = 0 cells.

So if you look at the data frame Infil_Data.Time.1, the "m" column contains nothing. Just a column with 517 rows of nothing. Now look at the Q_new data frame. The Vol..mL. values correspond to when Time = 0 (see Infil_Data.Time.1). I would like the value 63 to be repeated 12 times in column "m". And then value 82 to be repeated 12 times in column "m". I would like the final data frame to look like the last table I provided in the post above.

Does that make sense or do you need more information?

Cheers

-Z

I used the assign function because I thought that I could assign each row from column "m" a value. I also tried messing around with the match function, but didn't come out with my desired results. Plus, I am not sure if I was using it correctly. Any help would be most appreciated.

Cheers,

-Z

For future reference this is the way you should present a reprex, and I believe this is what you want to do but using data wrangling instead of loops

library(dplyr)
Q_new <- tibble::tribble(~Site.ID, ~Vol..mL., "H1", 63L, "H2", 82L, "H3", 
                         +                 69L)
Infil_Data.Time.1 <- tibble::tribble(~m, ~Time, ~Site.ID, ~Vol..mL., NA, 0L, "H1", 
                                     63, NA, 30L, "H1", 62, NA, 60L, "H1", 60, NA, 90L, "H1", 
                                     59, NA, 120L, "H1", 58, NA, 150L, "H1", 56, NA, 180L, "H1", 
                                     54, NA, 210L, "H1", 52.5, NA, 240L, "H1", 50, NA, 270L, "H1", 
                                     48.5, NA, 300L, "H1", 46.5, NA, 0L, "H2", 82, NA, 30L, "H2", 
                                     77, NA, 60L, "H2", 73, NA, 90L, "H2", 68, NA, 120L, "H2", 
                                     65, NA, 150L, "H2", 61, NA, 180L, "H2", 56, NA, 210L, "H2", 
                                     52, NA, 240L, "H2", 47.5, NA, 270L, "H2", 42.5, NA, 300L, 
                                     "H2", 37.5)
Infil_Data.Time <- Infil_Data.Time.1 %>% 
    left_join(Q_new, by = 'Site.ID') %>% 
    mutate(m = Vol..mL..y) %>% 
    select(m, Time, Site.ID, Vol..mL. = Vol..mL..x)

Infil_Data.Time
#> # A tibble: 22 x 4
#>        m  Time Site.ID Vol..mL.
#>    <int> <int> <chr>      <dbl>
#>  1    63     0 H1          63  
#>  2    63    30 H1          62  
#>  3    63    60 H1          60  
#>  4    63    90 H1          59  
#>  5    63   120 H1          58  
#>  6    63   150 H1          56  
#>  7    63   180 H1          54  
#>  8    63   210 H1          52.5
#>  9    63   240 H1          50  
#> 10    63   270 H1          48.5
#> # ... with 12 more rows

Created on 2019-01-04 by the reprex package (v0.2.1)

1 Like

Thank you andrescs. I will make sure to present a reprex like that. I entered in what you provided. However, I am getting another error.

Infil_Data.Time.1 <- Infil_Data.Time.1 %>% left_join(Q_new, by = "site.ID") %>%
mutate(m = Vol..mL..y) %>% select(m, Time, Site.ID, Vol..mL. = Vol..mL..x)
#> Error in Infil_Data.Time.1 %>% left_join(Q_new, by = "site.ID") %>% mutate(m = Vol..mL..y) %>% : could not find function "%>%"

You have to load dplyr first library(dplyr)

I did install the package and I reinstalled it twice more. I found the issue. Your code suggestion was correct. I used a lowercase "s" for 'Site.ID' instead of an uppercase "S". Thank you for your help again. That is exactly what I wanted.

Could you explain why my code on the original post does not work?

I'm sorry I really don't understand the logic behind your code, I just realized what you are trying to do when I saw the example dataframes

If you are going to be ussing r for analizing your data you need to have in mind that unlike VBA there is not need to manually iterate over your data, R is specificaly tailored for wrangling data in a more efficient way.

I think that a good resourse for you to read is this book https://r4ds.had.co.nz/ by Hadley Wickham

I'll keep that in mind for future problems. Thanks again!

If your question's been answered, would you mind choosing a solution? It helps other people see which questions still need help, or find solutions if they have similar problems. Here’s how to do it:

1 Like

You code in the original post does not work for several reason

  • while (!is.null(Q_new$Vol..mL)) will do an infinite loop, because in your data the column Vol.mL in Q_new is not null, and won't be null ever. I assumed you want to iterate on this colum
  • x %>% f(y, z) works like f(x, y, z). So you can't to a pipe chain like you've done.
  • assign takes a character as first argument. You can pipe it with the previous result you have
  • (next)(x) is not a correct call. next is not needed, unless you want to go to next x before the end of the for loop.

The solution given by @andresrcs is way better than a for loop with index. However, you can indeed use for loops and also vectorisation to go through this

Infil_Data.Time.1 <- tibble::tribble(~m, ~Time, ~Site.ID, ~Vol..mL, NA, 0L, "H1", 
                                     63, NA, 30L, "H1", 62, NA, 60L, "H1", 60, NA, 90L, "H1", 
                                     59, NA, 120L, "H1", 58, NA, 150L, "H1", 56, NA, 180L, "H1", 
                                     54, NA, 210L, "H1", 52.5, NA, 240L, "H1", 50, NA, 270L, "H1", 
                                     48.5, NA, 300L, "H1", 46.5, NA, 0L, "H2", 82, NA, 30L, "H2", 
                                     77, NA, 60L, "H2", 73, NA, 90L, "H2", 68, NA, 120L, "H2", 
                                     65, NA, 150L, "H2", 61, NA, 180L, "H2", 56, NA, 210L, "H2", 
                                     52, NA, 240L, "H2", 47.5, NA, 270L, "H2", 42.5, NA, 300L, 
                                     "H2", 37.5)

R1 <- 0
# iterate on the data for Times == 0
for (val in Infil_Data.Time.1[Infil_Data.Time.1$Time == 0, "Vol..mL", drop = TRUE]) {
  # with vectorisation, fill value 12 by 12 according to vall
  Infil_Data.Time.1$m[(1:11) + (R1 * 11)] <- val
  # increment the indice for next twelve value
  R1 = R1 + 1
}
print(Infil_Data.Time.1, n = 22)
#> # A tibble: 22 x 4
#>        m  Time Site.ID Vol..mL
#>    <dbl> <int> <chr>     <dbl>
#>  1    63     0 H1         63  
#>  2    63    30 H1         62  
#>  3    63    60 H1         60  
#>  4    63    90 H1         59  
#>  5    63   120 H1         58  
#>  6    63   150 H1         56  
#>  7    63   180 H1         54  
#>  8    63   210 H1         52.5
#>  9    63   240 H1         50  
#> 10    63   270 H1         48.5
#> 11    63   300 H1         46.5
#> 12    82     0 H2         82  
#> 13    82    30 H2         77  
#> 14    82    60 H2         73  
#> 15    82    90 H2         68  
#> 16    82   120 H2         65  
#> 17    82   150 H2         61  
#> 18    82   180 H2         56  
#> 19    82   210 H2         52  
#> 20    82   240 H2         47.5
#> 21    82   270 H2         42.5
#> 22    82   300 H2         37.5

You see that

  • you don't need to use %>% in all situation
  • you can assign to a column in a data.frame simply using <-
  • you can use vectorisation to a vector directly. Here, one val is assign to 12 values in one assignment

Hope it is clearer. Look into @andresrcs advices for training about data wrangling. it will help you a lot, and code will be more readable and clearer.

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.