首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何拆分数据帧,应用某些函数,然后将其重新组合在一起?

如何拆分数据帧,应用某些函数,然后将其重新组合在一起?
EN

Stack Overflow用户
提问于 2018-07-04 06:36:54
回答 3查看 154关注 0票数 2

通常,我有一个包含数值变量和分类变量的数据框架,我希望根据分类变量拆分数值变量,执行一些操作,然后以数据框架的形式将其重新组合在一起。该操作依赖于类别中数值向量的整个部分,有时会返回不同长度的向量。我知道如何以一种丑陋的方式来做这件事(见下面的例子),但这似乎是一种常见的操作,所以我想知道是否有一种我不知道的更简单的方法。我特别想知道是否有使用tidyverse的解决方案。

这是我所说的一个例子。

代码语言:javascript
复制
df = data.frame(y=1:10, g=rep(c("a", "b"), each=5))

假设我想标准化变量y,使其在分类变量的每个级别上都在0到1之间。以下是完成此操作的一般方法:

代码语言:javascript
复制
do.call(
    rbind,
    lapply(unique(df$g),
           function(level) {
               y.current = df$y[df$g==level]

               ## perform some operation
               y.new = (y.current-min(y.current))/
                   (max(y.current)-min(y.current))

               return(data.frame(y=y.new,
                                 g=level))
           }
           )
)

这需要大量的输入,而且可读性不是很好。有没有更好的方法?

编辑:感谢你的精彩回答。我唯一感兴趣的是使用tidyverse实现这一点的完全通用的方法。如果我们将示例更改为数值向量的大小减小但大于1的操作,则group_by/mutate/summarize组合将不起作用。例如,假设我想删除每个组中的最大值。我能做到

代码语言:javascript
复制
library(dplyr)
df = data.frame(y=1:10, g=rep(c("a", "b"), each=5))
trans_df = df %>%
    group_by(g) %>%
    do(y=.$y[-which.max(.$y)])

变换后的数据帧trans_df具有每个级别具有一个观察值的分组变量,并且变换后的变量作为分组变量的每个级别的列表。我可以使用base R将其放入原始格式

代码语言:javascript
复制
data.frame(g=rep(trans_df$g, times=sapply(trans_df$y, length)),
           y=do.call(c, trans_df$y))

但是我如何使用tidyverse来完成这项工作呢

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-07-04 06:55:11

使用data.table:

代码语言:javascript
复制
library(data.table)
df=as.data.table(df)
df[,(y-min(y))/(max(y)-min(y)),by=g]
    g   V1
 1: a 0.00
 2: a 0.25
 3: a 0.50
 4: a 0.75
 5: a 1.00
 6: b 0.00
 7: b 0.25
 8: b 0.50
 9: b 0.75
10: b 1.00
票数 2
EN

Stack Overflow用户

发布于 2018-07-04 06:53:33

这是经典的拆分-应用-合并方法。您通过分类变量进行分组,将某些函数应用于各个组,然后重新组合在一起。在dplyr中,这是由group_by处理的。

代码语言:javascript
复制
df <- data.frame(y=1:10, g=rep(c("a", "b"), each=5))

library(dplyr)
df %>%
  group_by(g) %>% 
  mutate(y2 = (y - min(y)) / (max(y) - min(y)))
#> # A tibble: 10 x 3
#> # Groups:   g [2]
#>        y g        y2
#>    <int> <fct> <dbl>
#>  1     1 a      0   
#>  2     2 a      0.25
#>  3     3 a      0.5 
#>  4     4 a      0.75
#>  5     5 a      1   
#>  6     6 b      0   
#>  7     7 b      0.25
#>  8     8 b      0.5 
#>  9     9 b      0.75
#> 10    10 b      1

df %>%
  group_by(g) %>% 
  top_n(-4, y)
#> # A tibble: 8 x 2
#> # Groups:   g [2]
#>       y g    
#>   <int> <fct>
#> 1     1 a    
#> 2     2 a    
#> 3     3 a    
#> 4     4 a    
#> 5     6 b    
#> 6     7 b    
#> 7     8 b    
#> 8     9 b

reprex package创建于2018-07-03 (v0.2.0)。

票数 0
EN

Stack Overflow用户

发布于 2018-07-04 06:57:00

在base R中,您可以这样做:

代码语言:javascript
复制
df$y <- ave(df$y,df$g, FUN = function(y) (y - min(y))/(max(y) - min(y)))
#       y g
# 1  0.00 a
# 2  0.25 a
# 3  0.50 a
# 4  0.75 a
# 5  1.00 a
# 6  0.00 b
# 7  0.25 b
# 8  0.50 b
# 9  0.75 b
# 10 1.00 b

或者这个也有同样的效果:

代码语言:javascript
复制
split(df$y,df$g) <- tapply(df$y, df$g, function(y) (y - min(y))/(max(y) - min(y)))

如果您需要处理data.frame的其他变量,则会更加灵活:

代码语言:javascript
复制
by_ <- by(df, df$g, function(x) transform(x, y = (y - min(y))/(max(y) - min(y))))
do.call(rbind, by_)
#         y g
# a.1  0.00 a
# a.2  0.25 a
# a.3  0.50 a
# a.4  0.75 a
# a.5  1.00 a
# b.6  0.00 b
# b.7  0.25 b
# b.8  0.50 b
# b.9  0.75 b
# b.10 1.00 b
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51163629

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档