Batbr
Batbr

Reputation: 71

loop to create a dataframe with new column, then combine them together

I want to duplicate my dataset on different flight altitude levels. I can do it manually creating dataframes with differing levels of altitude and then rbind them together. But, i want to make it faster by involving a for loop?

this is the example dataset:

structure(list(heading = c(0L, 71L, 132L, 143L, 78L, 125L, 0L, 
171L, 165L, 159L), thermal = c(1.25823300871478, 1.2972715238927, 
1.65348398199965, 2.04165937130312, 1.496194948775, 1.70668245624966, 
1.32775326817617, 1.37003605552932, 1.85841102388127, 1.20642577473389
), WS = c(17.1590022110329, 7.60663206413036, 16.3515501561529, 
15.8336908137001, 7.11013207359218, 8.69420768960291, 5.23228331387401, 
10.2762569508197, 3.79321542059933, 4.80008774506314), trackId = structure(c(3L, 
3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L), .Label = c("ke1601", "ke1607", 
"mwb1501", "mwb1502", "mwb1503", "mwb1504", "nsm1605", "rcees17110", 
"rcees17111", "X27230893", "X27231081", "X27233186", "X27234135", 
"X52409530"), class = "factor")), row.names = c(NA, 10L), class = "data.frame")

I was coding manually like this:

msl100 <- df %>% mutate(alt = 100)
msl200 <- df %>% mutate(alt = 200)
msl300 <- df %>% mutate(alt = 300)
msl400 <- df %>% mutate(alt = 400)
msl500 <- df %>% mutate(alt = 500)

df1 <- rbind(msl100, .........)

I need to do this for every 100 meters up to height 5100 meters.

Upvotes: 0

Views: 74

Answers (5)

Maurits Evers
Maurits Evers

Reputation: 50668

Another (fast) data.table-based alternative would be to do

library(data.table)
setDT(df)[, .(alt = seq(100, 5100, 100)), by = names(df)]
#    heading  thermal        WS trackId  alt
# 1:       0 1.258233 17.159002 mwb1501  100
# 2:       0 1.258233 17.159002 mwb1501  200
# 3:       0 1.258233 17.159002 mwb1501  300
# 4:       0 1.258233 17.159002 mwb1501  400
# 5:       0 1.258233 17.159002 mwb1501  500
#---
#506:     159 1.206426  4.800088 mwb1501 4700
#507:     159 1.206426  4.800088 mwb1501 4800
#508:     159 1.206426  4.800088 mwb1501 4900
#509:     159 1.206426  4.800088 mwb1501 5000
#510:     159 1.206426  4.800088 mwb1501 5100

Upvotes: 0

thelatemail
thelatemail

Reputation: 93803

This can be done purely through a cbind as the rows of the original data will repeat:

cbind(dat, alt=rep(seq(100,5100,100), each=nrow(dat)))

This should be much faster than looping over values.

Upvotes: 2

Parfait
Parfait

Reputation: 107567

Consider a cross join merge:

expanded_df <- merge(df, data.frame(alt=seq(100, 5100, 100)), by = NULL)

Upvotes: 1

www
www

Reputation: 39154

We can use crossing from the tidyr package.

library(dplyr)
library(tidyr)

df2 <- crossing(df, tibble(alt = seq(100, 5100, 100)))

If the order is important, create an ID column, arrage it, and then delete it.

df3 <- df %>%
  mutate(ID = 1:n()) %>%
  crossing(tibble(alt = seq(100, 5100, 100))) %>%
  arrange(alt, ID) %>%
  select(-ID)

Upvotes: 0

Ronak Shah
Ronak Shah

Reputation: 388807

Create a sequence, use lapply to loop over it transform to add new column and rbind

do.call(rbind, lapply(seq(100, 5100, 100), function(x) transform(df, alt = x)))

#   heading  thermal        WS trackId alt
#1        0 1.258233 17.159002 mwb1501 100
#2       71 1.297272  7.606632 mwb1501 100
#3      132 1.653484 16.351550 mwb1501 100
#4      143 2.041659 15.833691 mwb1501 100
#5       78 1.496195  7.110132 mwb1501 100
#6      125 1.706682  8.694208 mwb1501 100
#7        0 1.327753  5.232283 mwb1501 100
#8      171 1.370036 10.276257 mwb1501 100
#9      165 1.858411  3.793215 mwb1501 100
#10     159 1.206426  4.800088 mwb1501 100
#11       0 1.258233 17.159002 mwb1501 200
#12      71 1.297272  7.606632 mwb1501 200
#....

Using tidyverse that would be

library(dplyr)
library(purrr)

map_df(seq(100, 5100, 100), ~df %>% mutate(alt = .x))

Upvotes: 0

Related Questions