Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
R 通过间接引用列来修改数据框中的某些值_R_Dplyr_Tidyverse_Rlang - Fatal编程技术网

R 通过间接引用列来修改数据框中的某些值

R 通过间接引用列来修改数据框中的某些值,r,dplyr,tidyverse,rlang,R,Dplyr,Tidyverse,Rlang,我正在争论一些数据,我们将失败的数据分类到各个分类箱中,然后逐批计算每个分类箱的有限收益率 我有一个描述排序箱的元表。行以升序测试顺序排列,一些排序标签带有非语法名称 一些缺失值意味着100%的有限收益率,而另一些则反映了未定义的值,因为我们在流程的早期是零收益率我的任务是将前一组NA替换为1.00,视情况而定。 实现这一点的一种算法是从左到右(测试顺序降序),如果后续的限制产量不是NA,则将NA替换为1.00。在示例数据集的第一行中,我们不更改fail C,因为缺少pass。但是我们确实用1.

我正在争论一些数据,我们将失败的数据分类到各个分类箱中,然后逐批计算每个分类箱的有限收益率

我有一个描述排序箱的元表。行以升序测试顺序排列,一些排序标签带有非语法名称

一些缺失值意味着100%的有限收益率,而另一些则反映了未定义的值,因为我们在流程的早期是零收益率我的任务是将前一组
NA
替换为
1.00
,视情况而定。

实现这一点的一种算法是从左到右(测试顺序降序),如果后续的限制产量不是
NA
,则将
NA
替换为
1.00
。在示例数据集的第一行中,我们不更改
fail C
,因为缺少
pass
。但是我们确实用
1.00
替换
fail A
,因为
fail B
并不缺失

正确的示例输出为:

> fill_ones(yld_tbl, sort_tbl)
# A tibble: 4 x 5
    lot  pass `fail C` `fail B` `fail A`
  <chr> <dbl>    <dbl>    <dbl>    <dbl>
1  lot1    NA       NA     0.00     1.00
2  lot2    NA     0.00     0.80     1.00
3  lot3  0.49     1.00     0.50     0.98
4  lot4  0.70     0.95     0.74     0.99
>填充(yld、排序)
#一个tibble:4x5
批次通过“不合格C”`不合格B``不合格A`
1 lot1 NA 0.00 1.00
2 lot2 NA 0.00 0.80 1.00
3 lot3 0.49 1.00 0.50 0.98
4 lot4 0.70 0.95 0.74 0.99

为了生成输出表,我编写了以下函数:

library(rlang)
library(dplyr)

fill_ones <- function(df, meta) {
  fail_labels <- meta[meta$weight == 0, ]$label
  last_val <- NULL
  for ( i in length(fail_labels):1) {
    if (is.null(last_val)) last_val <- df$pass
    else last_val <- eval_tidy(sym(fail_labels[[i+1]]), df)
    this_name <- sym(fail_labels[[i]])
    this_val  <- eval_tidy(this_name, df)
    this_val[intersect(which(!is.na(last_val)), which(is.na(this_val)))] <- 1
    df <- mutate(df, !!!new_definition(this_name, this_val))
  }
  df
}
库(rlang)
图书馆(dplyr)

填充元素如果您将其视为“首先用1替换所有NAs,然后用NA替换第一个0之后的所有1”,则此问题会变得更容易

这里有两种方法,一种使用矩阵运算,另一种使用dplyr


在矩阵方法中,将值提取为数字矩阵,使用
apply
查找需要用NA替换的位置,然后返回它们

# extract as a matrix, with left-to-right bins
m <- as.matrix(yld_tbl[, sort_tbl$label])

# replace NAs with 1
m[is.na(m)] <- 1

# find 1s happening after a zero in each row
after_zero <- t(apply(m == 0, 1, cumsum)) & (m == 1)

# replace them with NA
m[after_zero] <- NA

# return them in the table
yld_tbl[, sort_tbl$label] <- m

请注意,与基于矩阵的方法不同,这不会保留列的顺序。

按照OP的方法从左到右填充缺失的1.00,这可以使用
melt()
dcast()
rleid()
实现:

资料
yld\u tbl我不知道你是如何填写1的。你能明确给出条件吗?@denis我更新了问题以更明确地解释这一点。如果两个后续的
NA
s,例如
lot5 NA 0.95 NA
将成为
lot5 NA 0.95 1.00 1.00
,会发生什么情况?@Uwe,是的,在您的示例中,后面的
NA
将变成
1.00
。但是隐含的通过率是
0.95
,因此示例行需要阅读:
lot5 0.95 0.95 NA
变成
lot5 0.95 0.95 1.00 1.00
。谢谢!这些方法看起来很有趣。两者都避免显式地在列上循环。我更喜欢这个。传入的数据以垂直列开始,因此我可以使用
排列(…,fill=1.00)
在传入的过程中执行
replace\u na()
操作。我有一个按顺序排列的列名表,因此对列重新排序只是一个
select(lot,!!!syms(sort\u tbl$label))
。我试图了解
cumsum(value==0)
正在做什么。数值向量
yld_tbl$值
将转换为逻辑向量。我猜
cumsum()
会因为
>0
而强制将其恢复为数值?因此,我们在一个批次中添加零的数量,如果有,我们将
值==1
条目替换为
NA
。那太圆滑了!这是正确的-‘cumsum(x==0)’将是到目前为止的零的数量,‘cumsum(x==0)>0’意味着“至少有一个零”。“在第一个某某之后,做这个”是一个很好用的成语,谢谢。我个人还没有使用DT,但是有这样一个语法的例子很好。惊人的组合。
library(rlang)
library(dplyr)

fill_ones <- function(df, meta) {
  fail_labels <- meta[meta$weight == 0, ]$label
  last_val <- NULL
  for ( i in length(fail_labels):1) {
    if (is.null(last_val)) last_val <- df$pass
    else last_val <- eval_tidy(sym(fail_labels[[i+1]]), df)
    this_name <- sym(fail_labels[[i]])
    this_val  <- eval_tidy(this_name, df)
    this_val[intersect(which(!is.na(last_val)), which(is.na(this_val)))] <- 1
    df <- mutate(df, !!!new_definition(this_name, this_val))
  }
  df
}
# extract as a matrix, with left-to-right bins
m <- as.matrix(yld_tbl[, sort_tbl$label])

# replace NAs with 1
m[is.na(m)] <- 1

# find 1s happening after a zero in each row
after_zero <- t(apply(m == 0, 1, cumsum)) & (m == 1)

# replace them with NA
m[after_zero] <- NA

# return them in the table
yld_tbl[, sort_tbl$label] <- m
library(dplyr)
library(tidyr)

yld_tbl %>%
  gather(label, value, -lot) %>%
  arrange(lot, match(label, sort_tbl$label)) %>%
  replace_na(list(value = 1)) %>%
  group_by(lot) %>%
  mutate(value = ifelse(cumsum(value == 0) > 0 & value == 1, NA, value)) %>%
  spread(label, value)
library(data.table)
mDT <- melt(setDT(yld_tbl), id.var = "lot")
mDT[
  mDT[, grp := rleid(is.na(value)), by = lot][, .I[is.na(value) & grp > 1]]
  , value := 1][
    , dcast(.SD, lot ~ variable)]
    lot pass fail C fail B fail A
1: lot1   NA     NA   0.00   1.00
2: lot2   NA   0.00   0.80   1.00
3: lot3 0.49   1.00   0.50   0.98
4: lot4 0.70   0.95   0.74   0.99
5: lot5 0.95   0.95   1.00   1.00
yld_tbl <- tibble::tribble(  ~lot, ~pass, ~`fail C`, ~`fail B`, ~`fail A`,
                             "lot1",    NA,        NA,      0.00,        NA,
                             "lot2",    NA,      0.00,      0.80,        NA,
                             "lot3",  0.49,        NA,      0.50,      0.98,
                             "lot4",  0.70,      0.95,      0.74,      0.99,
                             "lot5",  0.95,      0.95,        NA,        NA)