#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
подход:
- объедините имена столбцов, если colum равно 1.
- когда мы ищем первый столбец с 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