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
答案 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.frame
或data.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)
另一个dplyr
和slice
的替代项,其中我们将每个行号重复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 });
});
});
}
});