复制data.frame的每一行并指定每行的复制数

时间:2010-05-24 04:46:12

标签: r dataframe replicate

df <- data.frame(var1=c('a', 'b', 'c'), var2=c('d', 'e', 'f'), freq=1:3)

扩展上面data.frame的前两列的最简单方法是什么呢? 每行显示“freq”列中指定的次数?

换句话说,请从这里开始:

df
  var1 var2 freq
1    a    d    1
2    b    e    2
3    c    f    3

对此:

df.expanded
  var1 var2
1    a    d
2    b    e
3    b    e
4    c    f
5    c    f
6    c    f

10 个答案:

答案 0 :(得分:142)

这是一个解决方案:

df.expanded <- df[rep(row.names(df), df$freq), 1:2]

结果:

    var1 var2
1      a    d
2      b    e
2.1    b    e
3      c    f
3.1    c    f
3.2    c    f

答案 1 :(得分:40)

使用expandRows()包中的splitstackshape

library(splitstackshape)
expandRows(df, "freq")

简单的语法,非常快,适用于data.framedata.table

<强>结果:

    var1 var2
1      a    d
2      b    e
2.1    b    e
3      c    f
3.1    c    f
3.2    c    f

答案 2 :(得分:37)

旧问题,tidyverse中的新动词:

library(tidyr) # version >= 0.8.0
df <- data.frame(var1=c('a', 'b', 'c'), var2=c('d', 'e', 'f'), freq=1:3)
df %>% 
  uncount(freq)

    var1 var2
1      a    d
2      b    e
2.1    b    e
3      c    f
3.1    c    f
3.2    c    f

答案 3 :(得分:17)

@ neilfws的解决方案适用于data.frame,但不适用于data.table,因为它们缺少row.names属性。这种方法适用于:

df.expanded <- df[rep(seq(nrow(df)), df$freq), 1:2]

data.table的代码有点清洁:

# convert to data.table by reference
setDT(df)
df.expanded <- df[rep(seq(.N), freq), !"freq"]

答案 4 :(得分:3)

如果您必须对非常大的data.frames执行此操作,我建议将其转换为data.table并使用以下内容,这应该运行得更快:

library(data.table)
dt <- data.table(df)
dt.expanded <- dt[ ,list(freq=rep(1,freq)),by=c("var1","var2")]
dt.expanded[ ,freq := NULL]
dt.expanded

了解此解决方案的速度有多快:

df <- data.frame(var1=1:2e3, var2=1:2e3, freq=1:2e3)
system.time(df.exp <- df[rep(row.names(df), df$freq), 1:2])
##    user  system elapsed 
##    4.57    0.00    4.56
dt <- data.table(df)
system.time(dt.expanded <- dt[ ,list(freq=rep(1,freq)),by=c("var1","var2")])
##    user  system elapsed 
##    0.05    0.01    0.06

答案 5 :(得分:2)

另一个dplyrslice的替代项,其中我们将每个行号重复freq

library(dplyr)

df %>%  
  slice(rep(seq_len(n()), freq)) %>% 
  select(-freq)

#  var1 var2
#1    a    d
#2    b    e
#3    b    e
#4    c    f
#5    c    f
#6    c    f

seq_len(n())部分可用以下任何一种替换。

df %>% slice(rep(1:nrow(df), freq)) %>% select(-freq)
#Or
df %>% slice(rep(row_number(), freq)) %>% select(-freq)
#Or
df %>% slice(rep(seq_len(nrow(.)), freq)) %>% select(-freq)

答案 6 :(得分:0)

另一种可能性是使用tidyr::expand

library(dplyr)
library(tidyr)

df %>% group_by_at(vars(-freq)) %>% expand(temp = 1:freq) %>% select(-temp)
#> # A tibble: 6 x 2
#> # Groups:   var1, var2 [3]
#>   var1  var2 
#>   <fct> <fct>
#> 1 a     d    
#> 2 b     e    
#> 3 b     e    
#> 4 c     f    
#> 5 c     f    
#> 6 c     f

vonjd's answer 的单线版本:

library(data.table)

setDT(df)[ ,list(freq=rep(1,freq)),by=c("var1","var2")][ ,freq := NULL][]
#>    var1 var2
#> 1:    a    d
#> 2:    b    e
#> 3:    b    e
#> 4:    c    f
#> 5:    c    f
#> 6:    c    f

reprex package(v0.2.1)于2019-05-21创建

答案 7 :(得分:0)

我知道不是这种情况,但是如果您需要保留原始的freq列,则可以与tidyverse一起使用另一种rep方法:

library(purrr)

df <- data.frame(var1=c('a', 'b', 'c'), var2=c('d', 'e', 'f'), freq=1:3)

df %>% 
  map_df(., rep, .$freq)
#> # A tibble: 6 x 3
#>   var1  var2   freq
#>   <fct> <fct> <int>
#> 1 a     d         1
#> 2 b     e         2
#> 3 b     e         2
#> 4 c     f         3
#> 5 c     f         3
#> 6 c     f         3

reprex package(v0.3.0)于2019-12-21创建

答案 8 :(得分:0)

我们可以使用uncount中的tidyr

library(tidyr)
df %>% uncount(freq)

答案 9 :(得分:0)

实际上。使用向量和索引的方法。我们也可以达到相同的结果,并且更容易理解:

router.get("/youtube/callback", function(req, res) {
    // Create an OAuth2 client object from the credentials in our config file
    const oauth2Client = new OAuth2(
      CONFIG.oauth2Credentials.client_id,
      CONFIG.oauth2Credentials.client_secret,
      CONFIG.oauth2Credentials.redirect_uris[0]
    );
  
    if (req.query.error) {
      // The user did not give us permission.
      return res.redirect("/");
    } else {
      oauth2Client.getToken(req.query.code, function(err, token) {
        if (err) return res.redirect("/");
  
        // Store the credentials given by google into a jsonwebtoken in a cookie called 'jwt'
        res.cookie("jwt", jwt.sign(token, CONFIG.JWTsecret));
        
        // return res.redirect("/get_some_data");
  
        if (!req.cookies.jwt) {
          // We haven't logged in
          return res.redirect("/");
        }
      
        // Add this specific user's credentials to our OAuth2 client
        oauth2Client.credentials = jwt.verify(req.cookies.jwt, CONFIG.JWTsecret);
      
        // Get the youtube service
        const service = google.youtube("v3");
  
        const url = `https://www.googleapis.com/oauth2/v1/userinfo?access_token=${token[Object.keys(token)[0]]}`;
  
        // ================ mark 1 ====================
        const get_data = async () => {
          try {
            const response = await nf(url);
            const json = await response.json();
            return json;
          } catch (error) {
            console.log(error);
          }
        };
  
        // Get 50 of the user's subscriptions (the channels they're subscribed to)
        service.subscriptions
          .list({
            auth: oauth2Client,
            mine: true,
            part: "snippet,contentDetails",
            maxResults: 50
          })
          // ================ mark 2 ====================
          // remember to add async here
          .then(async (response) => { 
             // ================ mark 2 ====================
             const diomerda = await get_data()
  
            // Render the profile view, passing the subscriptions to it
            return res.render("./user/dashboard", { subscriptions: response.data.items, diomerda: diomerda });
          });
  
      });
    }
  });