根据列值通过行操作创建变量

问题描述 投票:0回答:1

样本数据

# Set seed for reproducibility
set.seed(123)

# Create a sample dataframe with 100 observations
n_obs <- 100
df <- data.frame(
  serial_id = 1:n_obs,
  code_1 = sample(c("yes", "no"), n_obs, replace = TRUE),
  code_2 = sample(c("yes", "no"), n_obs, replace = TRUE),
  code_3 = sample(c("yes", "no"), n_obs, replace = TRUE),
  type_1 = sample(c("A", "B", "C", "D"), n_obs, replace = TRUE),
  type_2 = sample(c("A", "B", "C", "D"), n_obs, replace = TRUE),
  type_3 = sample(c("A", "B", "C", "D"), n_obs, replace = TRUE)
)

我正在尝试创建一个满足以下逻辑的变量:

  1. 对于每一行:如果任何 code_* 列具有“yes”,并且相应的 type_* 列(例如:code_1 对应于 type_1 等)具有“A”,则新变量采用“1”。
  2. 对于每一行:如果任何 code_* 列具有“yes”,并且相应的 type_* 列(例如:code_1 对应于 type_1 等)具有“B”,则新变量采用“0”。即使存在应该导致“1”的“是”和“A”组合的逻辑,该规则也会覆盖之前的所有规则
  3. 对于每一行:如果在任何 type_* 列中“B”和“C”的对应 code_* 均为“no”,并且在其对应 type_x 中具有“C”的 code_* 中为“yes” ,那么 new_var == 1

我不知道如何根据最后一个字符(1,2,3,4,5,6.......)获取相应列的名称,然后对列执行行操作那个孤立的行。 原始数据大约有20对这样的code_*和type_*。所以,我正在尝试想出一些可迭代的东西。

r mutate rowwise
1个回答
0
投票

转换为 long,将代码和类型配对转换为更宽的格式,应用

serial_id
any()
的规则,然后将新变量左连接回
serial_id
上的原始数据集。这应该适用于您拥有的尽可能多的代码/类型对。

# Set seed for reproducibility
set.seed(123)

# Create a sample dataframe with 100 observations
library(data.table)
n_obs <- 100
df <- data.table(
  serial_id = 1:n_obs,
  code_1 = sample(c("yes", "no"), n_obs, replace = TRUE),
  code_2 = sample(c("yes", "no"), n_obs, replace = TRUE),
  code_3 = sample(c("yes", "no"), n_obs, replace = TRUE),
  type_1 = sample(c("A", "B", "C", "D"), n_obs, replace = TRUE),
  type_2 = sample(c("A", "B", "C", "D"), n_obs, replace = TRUE),
  type_3 = sample(c("A", "B", "C", "D"), n_obs, replace = TRUE)
)

# Convert to long format
df_long <- melt(df, id.vars = 'serial_id')
df_long[, type := tstrsplit(variable, "_", keep = 1)]
df_long[, index := tstrsplit(variable, "_", keep = 2)]

# Cast to a paired wide format.
df_wide <- dcast(df_long, serial_id + index ~ type,
                 value.var = "value")

# Apply rules
# Rule 1) Any yes + A => new_var = 1.
df_wide[, new_var := ifelse(any(code == "yes" & type == "A"), 1, NA_real_),
        by = serial_id]

# Rule 2) Any yes + B => new_var = 0, Overwrite rule 1, not rule 2
df_wide[, new_var := ifelse(any(code == "yes" & type == "B"), 0, new_var),
        by = serial_id]

# Rule 3) all(no + B, no + C, yes + C) => new_var = 1.  Overwrite rule 2.
# Example, serial_id = 38.
df_wide[, new_var := 
          ifelse(any(code == "no" & type == "B") &
                   any(code == "no" & type == "C") &
                   any(code == "yes" & type == "C"), 1, new_var),
        by = serial_id]

# Join back to the original data frame
df[df_wide[, .SD[1], by = serial_id], 
   new_var := new_var, on = .(serial_id)]
© www.soinside.com 2019 - 2024. All rights reserved.