R:对组内的子组重新编号,每次从1开始

时间:2015-10-31 16:37:52

标签: r

我所拥有的是一个数据集“df”,它在组内有子组,除了子组普遍编号为1-N,而不是每组中的1-n。目前它看起来像这样:

df = data.frame( c( rep(58, 10), rep(59, 12) ), 
                 c( rep(417, 4), rep(418, 5), rep(419, 1), rep(420, 7), 
                   rep(421, 5) ) )

colnames(df) = c("group", "subgroup_global")

df

     group      subgroup_global
1      58              417
2      58              417
3      58              417
4      58              417
5      58              418
6      58              418
7      58              418
8      58              418
9      58              418
10     58              419
11     59              420
12     59              420
13     59              420
14     59              420
15     59              420
16     59              420
17     59              420
18     59              421
19     59              421
20     59              421
21     59              421
22     59              421

我想把它变成这个,所以每个组中的第一个子组重新开始为1:

       group   subgroup_global subgroup
1      58              417         1
2      58              417         1
3      58              417         1
4      58              417         1
5      58              418         2
6      58              418         2
7      58              418         2
8      58              418         2
9      58              418         2
10     58              419         3
11     59              420         1
12     59              420         1
13     59              420         1
14     59              420         1
15     59              420         1
16     59              420         1
17     59              420         1
18     59              421         2
19     59              421         2
20     59              421         2
21     59              421         2
22     59              421         2

我已经找到了一个非常麻烦的方法,基本上有两个嵌套循环:

renumber <- function(c) {
                c$subgroup <- 1
                x <- which(!duplicated(c$subgroup_global))
                c[x, "subgroup"] <- 1:length(x)
                for(i in x) {
                        val = c[i, "subgroup"]
                        valGlobal = c[i, "subgroup_global"]
                        rows = which(c$subgroup_global == as.numeric(valGlobal))
                        c[rows, "subgroup"] = val
                        }
                c
}

接下来,我在数据集的每个组中迭代这个“重新编号”函数(你会注意到我潜入了基础R中的“过滤器”dplyr函数):

df_renumbered <- data.frame()
for(i in unique(df$group)) {
        df_partial <- filter(df, group == i)
        df_partial <- renumber(df_partial)
        df_renumbered <- rbind(df_renumbered, df_partial)
}
df_renumbered

除了效率低下之外,这段代码(在所有意图和目的上)花费了无限的时间在我的真实数据集上运行,其中包含200,000多行,3,000多个组和27,000多个子组。您能否使用dplyr或base R或两者的某些组合提供可行的解决方案?

3 个答案:

答案 0 :(得分:1)

您可以使用base函数ave

ave(df$subgroup_global,df$group,FUN=function(x) as.numeric(factor(x)))

答案 1 :(得分:0)

我更喜欢data.table

library(data.table)
setDT(df)
setkey(df, group, subgroup_global)
df[, subgroup:=as.factor(subgroup_global), by=group] # or
df[, subgroup:=as.numeric(as.factor(subgroup_global)), by=group]
# from data.table 1.9.6 on:
setDT(df)[, subgroup := frank(subgroup_global, ties.method = "dense"), by=group]
# (in this case setkey() above is not necessary)

答案 2 :(得分:0)

编辑:如果as.numeric(as.factor(x))不起作用(无论出于何种原因我还没弄明白),请使用以下函数对值进行重新编号。

# Create your data
df = data.frame( c( rep(58, 10), rep(59, 12) ), 
                 c( rep(417, 4), rep(418, 5), rep(419, 1), rep(420, 7), 
                    rep(421, 5) ) )
colnames(df) = c("group", "subgroup_global")

# Define function to replace values.
replace.values <- function(search, replace, x){
  return(replace[ match(x, search) ])
}

# Use by... to loop through all groups in the data.frame
# See how function inside by() works by setting: x <- df[df[,"group"]==df[1,"group"],]
df <- do.call("rbind", by(df, df[,"group"], function(x){
  # replace unique(subgroup_global) by values in the range 1:length(unique(subgroup_global))
  ux <- unique(x[,"subgroup_global"])
  return(cbind(x, subgroup=replace.values(ux, 1:length(ux), x[,"subgroup_global"])))
  }))
rownames(df) <- NULL

# Print you new df
print(df)

   group subgroup_global subgroup
1     58             417        1
2     58             417        1
3     58             417        1
4     58             417        1
5     58             418        2
6     58             418        2
7     58             418        2
8     58             418        2
9     58             418        2
10    58             419        3
11    59             420        1
12    59             420        1
13    59             420        1
14    59             420        1
15    59             420        1
16    59             420        1
17    59             420        1
18    59             421        2
19    59             421        2
20    59             421        2
21    59             421        2
22    59             421        2
老人回答:我知道很久以前就问过这个问题了。在过去,我还使用as.numeric(factor(x))来解决问题。但是,目前(2016.12.21)它不再适用于我的R版本(3.3.1)。

新方法是用1:length(unique(subgroup_global))范围内的值替换unique(subgroup_global)。我在下面解决了你的问题。

@-webkit-keyframes spin {
0% { -webkit-transform: rotate(0deg);}
100% { -webkit-transform: rotate(360deg);}
}
@-moz-keyframes spin {
0% { -moz-transform: rotate(0deg);}
100% { -moz-transform: rotate(360deg);}
}
@-o-keyframes spin {
0% { -o-transform: rotate(0deg);}
100% { -o-transform: rotate(360deg);}
}
@-ms-keyframes spin {
0% { -ms-transform: rotate(0deg);}
100% { -ms-transform: rotate(360deg);}
}
@-keyframes spin {
0% { transform: rotate(0deg);}
100% { transform: rotate(360deg);}
} 

header .spinner {
    position: absolute;
    width: 100%;
    text-align: center;
    margin: 0 auto;
    left: 0;
    -webkit-animation:spin 1s ease-out .5s;
    -moz-animation:spin 1s ease-out .5s;
    animation:spin 1s ease-out .5s;
    transform-origin: 50%;
}