Выполните цикл в R по столбцам и найдите первое значение, равное 1

#r #dataframe #loops #stata

Вопрос:

Я хотел бы просмотреть столбцы во фрейме данных (слева направо) и найти первое значение, равное 1 в каждой строке. Если значение равно 1, то я хотел бы добавить новый столбец в фрейм данных под названием x_time = 9,10,11,12 или 13 в зависимости от того, в какой момент времени значение 1 было найдено первым.

См. Пример данных

 df lt;- data.frame(x9 = c('$7', '$7', 2, '$7', 1, '$7'),  x10 = c('$7', 1, '$7', '$7', '$7', '$7'),  x11 = c('$7', '$7', 2, '$7', 1, '$7'),  x12 = c(1, 1, 2, '$7', '$7', '$7'),  x13 = c('$7', '$7', 2, '$7', 2, '$7'))   Desired output:   x9 x10 x11 x12 x13 x_time 1 $7 $7 $7 1 $7 12 2 $7 1 $7 1 $7 10 3 2 $7 2 2 2 NA 4 $7 $7 $7 $7 $7 NA 5 1 $7 1 $7 2 9 6 $7 $7 $7 $7 $7 NA   

Пожалуйста, дайте мне знать, какой подход был бы наиболее достаточным.

В Stata я бы просто создал глобальный макрос и прошелся по его содержимому:

 global varlist “x09 x10 x11 x12 x13”  gen x_time = . foreach var in $varlist {  replace x_time = substr("`var'",-2,.) if x_time == . amp; `var' == 1 }  

Комментарии:

1. Вы должны отредактировать свой df и желаемый результат. Третий ряд неверен.

2. Я так и сделал, спасибо, что указали.

3. Кстати, использование вами глобального макроса в Stata не является ни необходимым, ни хорошей практикой. Простое зацикливание foreach var in x09 x10 x11 x12 x13 было бы одним из нескольких других решений.

Ответ №1:

Вы можете зациклиться вот так

 vec lt;- c() for (k in 1:nrow(df)) {  if(length(which(as.vector(unlist(df[k,]))=="1"))gt;0){  vec[k] lt;- as.numeric(gsub("x","",colnames(df)[which(as.vector(unlist(df[k,]))=="1")[1]]))    }else{  vec[k] lt;- NA  }   }  df$x_time lt;- vec  

выход

 gt; df  x9 x10 x11 x12 x13 x_time 1 $7 $7 $7 1 $7 12 2 $7 1 $7 1 $7 10 3 2 $7 2 2 2 NA 4 $7 $7 $7 $7 $7 NA 5 1 $7 1 $7 2 9 6 $7 $7 $7 $7 $7 NA  

Комментарии:

1. Это логичное и статусное приложение, которое я мог бы легко понять. Спасибо.

Ответ №2:

Вот такой data.table подход

 library(data.table) # Convert to data.table, keep rownames as identifier setDT(df, keep.rownames = TRUE) # join molten data on df df[melt(df, id.vars = "rn")[value == 1, .SD[1], by = .(rn)],  x_time := gsub("x", "", i.variable),  on = .(rn)] # rn x9 x10 x11 x12 x13 x_time # 1: 1 $7 $7 $7 1 $7 12 # 2: 2 $7 1 $7 1 $7 10 # 3: 3 2 $7 2 2 2 lt;NAgt; # 4: 4 $7 $7 $7 $7 $7 lt;NAgt; # 5: 5 1 $7 1 $7 2 9 # 6: 6 $7 $7 $7 $7 $7 lt;NAgt;  

Ответ №3:

Вот такой tidyverse подход:

  1. объедините имена столбцов, если colum равно 1.
  2. когда мы ищем первый столбец с 1, мы могли бы использовать parse_number , чтобы выбрать первое число из строки!
 library(dplyr) library(tidyr)  df %gt;%   mutate(across(x9:x13, ~case_when(. == "1" ~ cur_column()), .names = 'new_{col}')) %gt;%  unite(New_Col, starts_with('new'), na.rm = TRUE, sep = ' ') %gt;%   mutate(x_time=parse_number(New_Col), .keep="unused")  

выход:

 x9 x10 x11 x12 x13 x_time 1 $7 $7 $7 1 $7 12 2 $7 1 $7 1 $7 10 3 2 $7 2 2 2 NA 4 $7 $7 $7 $7 $7 NA 5 1 $7 1 $7 2 9 6 $7 $7 $7 $7 $7 NA