根据相应的列r替换列值

时间:2019-07-23 19:51:20

标签: r tidyverse

我大约有60列不同的列,其中30列对应于其余30列的名称。我想根据其他对应值替换这30个列值。

  1. 样本数据:
df.wide<-data.frame(
  title=c("A","B","C","D"),
  IM.A=c(0.5,0.1,4.6,5.6),
  LV.A=c(0.7,0,2.5,5),
  IM.B=c(0.2,0.4,2.6,2.2),
  LV.B=c(1,2,4.5,5),
  IM.C=c(2,1,3,4),
  LV.C=c(3,2,5,1)
)

我还有更多列-IM.D ~~ LM.D ~~数据中的每个标题。

  1. 我已经将数据重整为很长的时间以提取唯一的列名称:
df.long <- gather(df.wide, element,value, IM.A:LV.C)
df.long <- select(df.long, c("element"))
df.long <- unique(df.long)
  1. 我已将LV和IM分离为不同的数据。
lv <- as.data.frame(df.long[grep("LV", df.long$element), ])
im <- as.data.frame(df.long[grep("IM", df.long$element), ])
  1. 我不确定如何从此处继续,但是基本上我想将列LV值更改为0(如果其对应的IM值小于2.5,并且我尚未在Internet上找到解决方案。) li>

最终数据如下所示:

df.wide<-data.frame(
  title=c("A","B","C","D"),
  IM.A=c(0.5,0.1,4.6,5.6),
  LV.A=c(0,0,2.5,5),
  IM.B=c(0.2,0.4,2.6,2.2),
  LV.B=c(0,0,4.5,0),
  IM.C=c(2,1,3,4),
  LV.C=c(0,0,5,1)
)

3 个答案:

答案 0 :(得分:3)

也许以长格式存储数据:

library(data.table)
setDT(df.wide)

dt.long = melt(df.wide, meas=patterns(IM = "^IM", LV = "^LV"))
dt.long[, variable := c("A","B","C")[variable]]

    title variable  IM  LV
 1:     A        A 0.5 0.7
 2:     B        A 0.1 0.0
 3:     C        A 4.6 2.5
 4:     D        A 5.6 5.0
 5:     A        B 0.2 1.0
 6:     B        B 0.4 2.0
 7:     C        B 2.6 4.5
 8:     D        B 2.2 5.0
 9:     A        C 2.0 3.0
10:     B        C 1.0 2.0
11:     C        C 3.0 5.0
12:     D        C 4.0 1.0

从这里开始,很容易进行编辑:

dt.long[IM < 2.5, LV := 0]

如果要使用tidyr :据我所知,gather不支持在转换为长格式时创建两列。函数的下一代pivot_longer可能。


我建议尽可能长时间继续使用长格式的数据,以避免进一步困扰变量名,但是如果您需要恢复宽格式,则可以...

res = dcast(dt.long, title ~ variable, value.var=c("IM", "LV"), sep=".")

   title IM_A IM_B IM_C LV_A LV_B LV_C
1:     A  0.5  0.2    2  0.0  0.0    0
2:     B  0.1  0.4    1  0.0  0.0    0
3:     C  4.6  2.6    3  2.5  4.5    5
4:     D  5.6  2.2    4  5.0  0.0    1

如果您想要相同的列顺序,则需要进一步的步骤:

setcolorder(res, names(df.wide))

   title IM.A LV.A IM.B LV.B IM.C LV.C
1:     A  0.5  0.0  0.2  0.0    2    0
2:     B  0.1  0.0  0.4  0.0    1    0
3:     C  4.6  2.5  2.6  4.5    3    5
4:     D  5.6  5.0  2.2  0.0    4    1

答案 1 :(得分:1)

您可以使用ifelse(df.wide$IM.A < 2.5, 0, df.wide$LV.A)

对于所有列,假设您的变量按照df.wideIM.xLV.x都紧随其后)中描述的方式隔开,则可以执行以下操作,其中3是LV的第一列,最后LV的列是7。

df.wide[,seq(3,7, by = 2)] <- sapply(seq(3,7, by = 2), function(x)
  ifelse(df.wide[,x-1] < 2.5, 0, df.wide[,x])  
)

但是正如@Frank指出的那样,您实际上应该尽可能长时间地使用长格式,以使这些操作更加简单。

答案 2 :(得分:1)

这是使用开发tidyr pivot_函数的一种方法。您可以通过运行devtools::install_github("tidyverse/tidyr")获得这些。

这展示了枢轴功能的spec功能,可让您灵活地指定重塑格式。它的工作方式是,规范的每一行都是原始数据帧的输入列(如果使用pivot_longer)。 .name列具有输入列名称,.value列具有您希望各个输入列中的值进入的新列的名称。在这里,我们希望将以"IM"开头的列中的所有值放入IM列中,并以类似的方式将LV放在其中。最后,我们指定其他变量如何映射到列(此处仅为letter)。

这使我们可以快速pivot_longer,用if_else进行所需的替换,然后pivot_wider回到原始格式。

library(tidyverse)
df.wide <- data.frame(
  title = c("A", "B", "C", "D"),
  IM.A = c(0.5, 0.1, 4.6, 5.6),
  LV.A = c(0.7, 0, 2.5, 5),
  IM.B = c(0.2, 0.4, 2.6, 2.2),
  LV.B = c(1, 2, 4.5, 5),
  IM.C = c(2, 1, 3, 4),
  LV.C = c(3, 2, 5, 1)
)

spec <- tibble(
  `.name` = df.wide %>% select(-title) %>% colnames(),
  `.value` = str_extract(`.name`, "^.{2}"),
  letter = str_extract(`.name`, ".{1}$")
)

df.wide %>%
  pivot_longer(spec = spec) %>%
  mutate(LV = if_else(IM < 2.5, 0, LV)) %>%
  pivot_wider(spec = spec)
#> # A tibble: 4 x 7
#>   title  IM.A  LV.A  IM.B  LV.B  IM.C  LV.C
#>   <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 A       0.5   0     0.2   0       2     0
#> 2 B       0.1   0     0.4   0       1     0
#> 3 C       4.6   2.5   2.6   4.5     3     5
#> 4 D       5.6   5     2.2   0       4     1

reprex package(v0.3.0)于2019-07-23创建