【问题标题】:Replace values into previous row with a condition用条件将值替换到上一行
【发布时间】:2018-12-03 12:41:28
【问题描述】:

我想获取 ID 列不以 00 开头的数据,并将此 ID 列的值附加到上一行的 Description 列的末尾。

然后将其余的值替换到上一行的 Name 列之后。我怎样才能用 R 做到这一点?

这里是虚拟数据的来源:https://docs.google.com/spreadsheets/d/1SbmaM8hXck-z5nsNfDMbhwijvAGPkPPBgQ_eY4JAMC8/edit?usp=sharing

ID      Year    Description  Name   User       Factor_1  Factor_2   Factor_3
0011    2016    blue colour  AA     James      Xfac      NA         NA
is nice XXX     XLM          Yfac   different  Yfac      NA         NA
0024    2017    red colour   DD     Mark       Zfac      NA         NA
is good YYY     STM          Lfac   unique     Zfac      NA         NA

我想拥有什么:

ID      Year    Description          Name   User  Factor_1   Factor_2   Factor_3
0011    2016    blue colour is nice  XXX    XLM   Yfac       different  Yfac
0024    2017    red colour is good   YYY    STM   Lfac       unique     Zfac

【问题讨论】:

  • 非零ID值是否总是跟在ID中的00值之后?
  • 请使用dput 提供示例数据,这样我们就知道我们正在处理什么......
  • @YOLO 是的,对
  • @Wimpel 我添加了上面的链接作为示例数据的来源

标签: r substring str-replace data-manipulation


【解决方案1】:

您想要将描述粘贴在一起的第一部分,
还有您想要移动变量的部分,因为您想要在“用户”列中添加“XXX”和“YYY”。

此外,在 Viveks 回答中,所有错误的行都粘贴了所有“正确”的行,这在您的示例中有效,但如果您有几行正确的行,然后是错误的行,则不行。 使用布尔值 (TRUE/FALSE) 有时可以正常工作,但在这种情况下,我认为您想使用整数索引,因为这样更容易引用“上一行”。这给了我代码:

rmlines <- which(!substr(df$ID,1,2)=="00")
df$Description[rmlines-1] <- paste(df$Description[rmlines-1], df[rmlines,1], sep=" ")
df[rmlines-1, 4:8] <- df[rmlines, 2:6]
df <- df[-rmlines,]

但还有一个问题需要考虑:您的列是什么类?
当我尝试它时,我将所有内容都视为一个角色,这意味着您可以很好地移动列。在您的数据中,有些可能是因素或其他因素,因此您可能想要更改类。我认为最简单的方法是先将其全部更改为字符,然后将其(返回)更改为您希望列成为的最终类。

# To change everything to character:
df <- as.data.frame(lapply(df, as.character), stringsAsFactors = FALSE)
# And to assign the right classes, you need to decide case-by-case:
df$Year <- as.integer(df$Year)
df$Factor_1 <- as.factor(df$Factor1) # Optionally provide levels

【讨论】:

  • 感谢您的回复!它有效,但我需要找到一个更强大的解决方案,以防我有很多带有 NA 的列。你能看看吗? stackoverflow.com/questions/53610694/…
  • 列的内容是什么、NA 或其他内容并不重要。要移动更多列,您可以将 4:8 和 2:6 替换为例如4:100 和 2:98,或者如果你不知道你有多少,你可以使用 4:ncol(df)2:(ncol(df)-2). It only means that the last 2 columns of the lines you are shifting right" get discarded. If you don't want that you can use 4:(ncol(df)+2)` 和 2:ncol(df),这样两个新列已创建,其中填充了您未分配任何内容的 NA。
  • 是的,我做到了,像上面一样工作。但这次的条件不同。我不需要将行粘贴到特定的顺序,而是需要将它们粘贴到最后一个非 NA 行的末尾,每行可能不同。如果您查看链接上的虚拟数据,我想您会更好地理解我的意思。 stackoverflow.com/questions/53610694/…
【解决方案2】:

这是dplyr的解决方案:

library(dplyr)

df %>% 
  bind_cols(df %>% rename_all(function(x) paste0(x, "_dummy"))) %>%
  mutate(
    Description = ifelse(substr(lead(ID), 1, 2) != "00", 
                         paste(Description, lead(ID)), Description),
    Name = lead(Year_dummy),
    User = lead(Description_dummy),
    Factor_1 = lead(Name_dummy),
    Factor_2 = lead(User_dummy),
    Factor_3 = lead(Factor_1_dummy)
  ) %>% select(-ends_with("dummy")) %>%
  filter(substr(ID, 1, 2) == "00")

输出:

    ID Year       Description Name User Factor_1  Factor_2 Factor_3
1 0011 2016 blue colour is nice  XXX  XLM     Yfac different     Yfac
2 0024 2017  red colour is good  YYY  STM     Lfac    unique     Zfac

如果您要处理大量列,dplyrbase R 的组合可以做到:

library(dplyr)

df_combo <- cbind(df, df)

df$Description <- ifelse(substr(lead(df$ID), 1, 2) != "00", 
                               paste(df$Description, lead(df$ID)), df$Description)

for (i in (ncol(df) + 4):ncol(df_combo)) {

  df_combo[[i]] <- lead(df_combo[[i - ncol(df) - 2]])

}

df_combo <- subset(df_combo, substr(ID, 1, 2) == "00")

df_descr <- subset(df, substr(ID, 1, 2) == "00")

df_final <- df_combo[, (ncol(df) + 1):ncol(df_combo)]

df_final$Description <- df_descr$Description

rm(df_descr, df_combo)

输出:

     ID Year       Description Name User Factor_1  Factor_2 Factor_3
1: 0011 2016 blue colour is nice  XXX  XLM     Yfac different     Yfac
2: 0024 2017  red colour is good  YYY  STM     Lfac    unique     Zfac

【讨论】:

  • 非常感谢!除了最后一列,我还有很多其他列。如何以相同的方式将它们从 ID 列不以 00 开头的位置粘贴到上一行?添加了 select(-ends_with("dummy"), Everything()),但列数增加了两倍。
  • 不幸的是,在这种情况下,您必须手动完成。假设您有一个名为 X 的列,您想将 Y 粘贴到前一行中。您将其放入语句中的方式与其他方式相同,例如如果我们从这里的示例继续 - (.. Factor_3 = lead(Factor_1_dummy), X = lead(Y_dummy)) 等等。
  • 我总共有 167 列。有没有其他方法可以达到同样的效果?
  • 谢谢!我接受了另一个答案,因为这对我来说很容易也更容易理解。但你的帮助也奏效了!为了为另一种情况提供更强大的解决方案,而不是将行粘贴到特定顺序,我想将它们粘贴到最后一个非 NA 行的末尾,每行可能不同。你能看一下吗? stackoverflow.com/questions/53610694/…
【解决方案3】:

使用 -

bools <- !substr(df$ID,1,2)=="00"
values <- df[bools,1]
df <- df[!bools,]
df$Description <- paste(df[substr(df$ID,1,2)=="00","Description"],values,sep=" ")
df

输出

    ID Year         Description Name  User Factor_1 Factor_2
1 0011 2016 blue colour is nice   AA James     Xfac       NA
3 0024 2017  red colour is good   DD  Mark     Zfac       NA
  Factor_3
1       NA
3       NA

【讨论】:

  • 描述栏看起来像这样:("blue colour", "red colour") c("is nice", "is good")。输出也完全不同。这是示例数据:docs.google.com/spreadsheets/d/…
  • @kimi_f109 代码有效吗?就像我说的那样,在我的情况下输出看起来会有所不同。它应该在你的情况下工作正常
  • 是的,但输出完全不同。我不知道在你的代码块中改变什么来达到结果。
  • @kimi_f109 就像我说你不必改变任何东西 :-) 我已经编辑了请检查
  • 这是我运行代码时的输出,这不是我想要的正确结果。请查收:docs.google.com/spreadsheets/d/…
猜你喜欢
  • 2019-03-23
  • 2021-04-15
  • 2017-08-14
  • 2022-07-06
  • 1970-01-01
  • 2018-08-13
  • 1970-01-01
  • 2020-01-31
  • 1970-01-01
相关资源
最近更新 更多