簡體   English   中英

根據其他列替換數據框中的列值

[英]Replace column value in a data frame based on other columns

我有按名稱和時間排序的以下數據框。

set.seed(100)
df <- data.frame('name' = c(rep('x', 6), rep('y', 4)), 
                 'time' = c(rep(1, 2), rep(2, 3), 3, 1, 2, 3, 4),
                 'score' = c(0, sample(1:10, 3), 0, sample(1:10, 2), 0, sample(1:10, 2))
                 )
> df
   name time score
1     x    1     0
2     x    1     4
3     x    2     3
4     x    2     5
5     x    2     0
6     x    3     1
7     y    1     5
8     y    2     0
9     y    3     5
10    y    4     8

df$score中有零,后跟未知數量的實際值,即df[1:4,] ,有時在兩個df$score == 0之間存在重疊的df$name ,即df[6:7,]

我想改變df$time ,其中df$score != 0 具體來說,如果df$name匹配,我想用df$score == 0分配最近上排的時間值。

以下代碼提供了良好的輸出,但我的數據有數百萬行,因此這種解決方案效率很低。

score_0 <- append(which(df$score == 0), dim(df)[1] + 1)

for(i in 1:(length(score_0) - 1)) {
  df$time[score_0[i]:(score_0[i + 1] - 1)] <-
    ifelse(df$name[score_0[i]:(score_0[i + 1] - 1)] == df$name[score_0[i]], 
           df$time[score_0[i]], 
           df$time[score_0[i]:(score_0[i + 1] - 1)])
 }

> df
   name time score
1     x    1     0
2     x    1     4
3     x    1     3
4     x    1     5
5     x    2     0
6     x    2     1
7     y    1     5
8     y    2     0
9     y    2     5
10    y    2     8

其中score_0給出了df$score == 0的索引。 我們看到df$time[2:4]現在都等於1,在df$time[6:7]只有第一個改變,因為第二個有df$name == 'y'和最近的上排與df$score == 0df$name == 'x' 最后兩行也已正確更改。

你可以這樣做:

library(dplyr)
df %>% group_by(name) %>% mutate(ID=cumsum(score==0)) %>% 
       group_by(name,ID) %>% mutate(time = head(time,1)) %>% 
       ungroup() %>%  select(name,time,score) %>% as.data.frame()

#       name time  score
# 1     x    1     0
# 2     x    1     8
# 3     x    1    10
# 4     x    1     6
# 5     x    2     0
# 6     x    2     5
# 7     y    1     4
# 8     y    2     0
# 9     y    2     5
# 10    y    2     9

使用dplyrdata.table解決方案:

library(data.table)
library(dplyr)

df %>%
  mutate(
    chck = score == 0,
    chck_rl = ifelse(score == 0, lead(rleid(chck)), rleid(chck))) %>% 
  group_by(name, chck_rl) %>% mutate(time = first(time)) %>% 
  ungroup() %>% 
  select(-chck_rl, -chck)

輸出:

# A tibble: 10 x 3
   name   time score
   <chr> <dbl> <int>
 1 x         1     0
 2 x         1     2
 3 x         1     9
 4 x         1     7
 5 x         2     0
 6 x         2     1
 7 y         1     8
 8 y         2     0
 9 y         2     2
10 y         2     3

解決方案僅使用data.table

library(data.table)

setDT(df)[, chck_rl := ifelse(score == 0, shift(rleid(score == 0), type = "lead"), 
    rleid(score == 0))][, time := first(time), by = .(name, chck_rl)][, chck_rl := NULL]

輸出:

   name time score
 1:    x    1     0
 2:    x    1     2
 3:    x    1     9
 4:    x    1     7
 5:    x    2     0
 6:    x    2     1
 7:    y    1     8
 8:    y    2     0
 9:    y    2     2
10:    y    2     3

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM