用不同的值替换组中的最后一个值

时间:2015-08-04 08:21:01

标签: r data.table dplyr

我的问题类似于this post,但区别在于不是用全0替换每个组/ id中的最后一个值,而是使用不同的值来替换每个组/ id中的最后一个值。

这是一个例子(我从上面的链接中借用了它):

          id  Time
1         1    3
2         1    10
3         1    1
4         1    0
5         1    9999
6         2    0
7         2    9
8         2    500
9         3    0
10        3    1

在上面的链接中,每个组/ id中的最后一个值被零替换为:

df %>%
  group_by(id) %>%
  mutate(Time = c(Time[-n()], 0))

输出

          id  Time
1         1    3
2         1    10
3         1    1
4         1    0
5         1    0
6         2    0
7         2    9
8         2    0
9         3    0
10        3    0

在我的情况下,我希望每个组/ id中的最后一个值被替换为不同的值。最初,每个组/ ID中的最后一个值是99995001。现在我想:99995取代,50012取代,192取代。所需的输出是:

          id  Time
1         1    3
2         1    10
3         1    1
4         1    0
5         1    5
6         2    0
7         2    9
8         2    12
9         3    0
10        3    92

我试过这个:

df %>%
  group_by(id) %>%
  mutate(Time = replace(Time, n(), c(5,12,92))),

但它不起作用。

2 个答案:

答案 0 :(得分:3)

这可以使用我在链接问题中发布的几乎相同的解决方案来解决。例如,只需将0L替换为所需的值

library(data.table)
indx <- setDT(df)[, .I[.N], by = id]$V1
df[indx, Time := c(5L, 12L, 92L)]
df
#     id Time
#  1:  1    3
#  2:  1   10
#  3:  1    1
#  4:  1    0
#  5:  1    5
#  6:  2    0
#  7:  2    9
#  8:  2   12
#  9:  3    0
# 10:  3   92

所以添加一些解释:

    对于未分组的数据,
  1. .Irow_number()1:n()中的dplyr1:nrow(df)相同,例如基础R中的.N
  2. n()dplyr中的.I[.N]类似,例如,某个组(或整个数据集)的大小。所以基本上当我按小组运行df时,我会检索每个小组的最后一行全局索引
  3. 下一步是将此索引用作Time中的行索引,同时使用:=运算符通过引用将所需值分配给dplyr
  4. 修改

    根据OP请求,这里有一个library(dplyr) df %>% group_by(id) %>% mutate(indx = n()) %>% ungroup() %>% mutate(Time = replace(Time, cumsum(unique(indx)), c(5, 12, 92))) %>% select(-indx) # Source: local data frame [10 x 2] # # id Time # 1 1 3 # 2 1 10 # 3 1 1 # 4 1 0 # 5 1 5 # 6 2 0 # 7 2 9 # 8 2 12 # 9 3 0 # 10 3 92 解决方案。您的原始解决方案无法正常工作,因为您正在按群组工作,因此您尝试将所有三个值传递给每个组。

    我能想到的唯一方法是首先计算组大小,然后取消组合,然后对这些位置的累积总和进行变异,这些行中的某些内容

     <body>
    <div class="navbar navbar-inverse">
        <div class="container-fluid">
            <div class="row">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                </div>
            </div>
    
    
        <div class="row">
            <div class="navbarunder">
                <div class="navbar-collapse collapse">
                    <ul class="nav navbar-nav">
                        <li>@Html.ActionLink("Home", "Index", "Home")</li>
                        <li>@Html.ActionLink("About", "About", "Home")</li>
                        <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
                    </ul>
                    @Html.Partial("_LoginPartial")
                </div>
            </div>
        </div>
    </div>
    </div>
    <div class="container body-content">
        @RenderBody()
        <hr />
    </div>
    
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @RenderSection("scripts", required: false)
    </body>
    

答案 1 :(得分:3)

使用data.table的另一种方法是创建另一个 data.table ,其中包含要替换为给定id的值,然后 join和通过引用更新(同时)。

require(data.table) # v1.9.5+ (for 'on = ' feature)
replace = data.table(id = 1:3, val = c(5L, 12L, 9L)) # from @David
setDT(df)[replace, Time := val, on = "id", mult = "last"]

#     id Time
#  1:  1    3
#  2:  1   10
#  3:  1    1
#  4:  1    0
#  5:  1    5
#  6:  2    0
#  7:  2    9
#  8:  2   12
#  9:  3    0
# 10:  3    9
  

data.table中,加入被视为子集的扩展。考虑在连接上对子集进行的任何操作都很自然。两个操作在某些行上执行某些操作

对于每个replace$id,我们在mult = "last"中找到最后一个匹配的行(df$id), 更新该行相应的val

v1.9.5 here的安装说明。希望这会有所帮助。