I'm trying to convert a SAS program into a R one and I have stumbled at the for() loop and array part. It keeps saying in the log:
"Error in for (. in i) seq_len(NBR_LIGNES_MAX) : 4 arguments passed to 'for' which requires 3" .
Can someone show me what I'm missing? My first thought is that I'm programming too much as SAS code in R. As for the data, I have 11 variables: 1 Id, 5 status, 5 dates. The date are linked with each status.
Before creating TR_HISTO_STATUT, the df was like :
ID status date
125521 1 2020年01月01日
125521 5 2022年05月06日
125521 4 2025年10月07日
999125 1 2020年02月02日
999125 4 2021年11月02日
888525 1 2021年03月30日
I transpose the data so I would have :
ID status1 status2 status3 date1 date2 date3
125521 1 5 4 2020年01月01日 2022年05月06日 2025年10月07日
999125 1 4 . 2020年02月02日 2021年11月02日 .
888525 1 . . 2021年03月30日 . .
Globally, I want the last status and the status before that with the corresponding dates (date1, ..., date5) by comparing those dates with DT_DEB and or DT_FIN.
Ex : For ID = 125521, DT_DEB is after date2 (2025年04月30日 vs 2022年05月06日). I would have the following result for that person:
ID status1 status2 status3 date1 date2 date3 DERN_STATUT DERN_DT_EFF AV_DERN_STATUT AV_DERN_DT_EFF
125521 1 5 4 2020年01月01日 2022年05月06日 2025年10月07日 2022年05月06日 2020年01月01日 5 1
and so on for the rest of my data.
Here's an example of the data before transposing : STATUT
Here's an example of the first lines of my data : TR_HISTO_STATUT
Here's my R code:
NBR_LIGNES_MAX <- 5
DT_DEB <- as.Date("2025年04月01日")
DT_FIN <- as.Date("2025年04月30日")
TR_HISTO_STATUT3 <- TR_HISTO_STATUT %>%
rowwise() %>%
for (i in seq_len(NBR_LIGNES_MAX)) {
for (j in seq((i + 1), (NBR_LIGNES_MAX - 1))) {
if (!is.na(DT_EFF_vec[i]) && DT_EFF_vec[i] < DT_DEB && is.na(DT_EFF_vec[j])) {
DERN_STATUT <- TR_HISTO_STATUT[,i]
DERN_DT_EFF <- TR_HISTO_STATUT[,i + NBR_LIGNES_MAX]
if (i > 1) {
AV_DERN_STATUT <- TR_HISTO_STATUT[, i - 1]
AV_DERN_DT_EFF <- TR_HISTO_STATUT[, i - 1 + NBR_LIGNES_MAX]
break
}
code <- 1
}
}
}
row$code <- code
row$DERN_STATUT <- DERN_STATUT
row$DERN_DT_EFF <- DERN_DT_EFF
row$AV_DERN_STATUT <- AV_DERN_STATUT
row$AV_DERN_DT_EFF <- AV_DERN_DT_EFF
row
}) %>%
ungroup()
vs the equivalent SAS code:
data TR_HISTO_STATUT3;
format DERN_DT_EFF AV_DERN_DT_EFF YYMMDD10.;
retain CODE DERN_STATUT DERN_DT_EFF;
set TR_HISTO_STATUT;
array tvar_statut[&NBR_LIGNES_MAX] statut1-statut&NBR_LIGNES_MAX;
array tvar_DT_EFF[&NBR_LIGNES_MAX] DT_EFF1-DT_EFF&NBR_LIGNES_MAX;
code = 0;
do i = 1 to &NBR_LIGNES_MAX;
do j = i+1 to &NBR_LIGNES_MAX-1;
if tvar_DT_EFF[i] NE . and tvar_DT_EFF[i] < &DT_DEB and tvar_DT_EFF[j] = . then do;
DERN_STATUT = tvar_statut[i];
DERN_DT_EFF = tvar_DT_EFF[i];
if i > 1 then AV_DERN_STATUT = tvar_statut[i-1];
if i > 1 then AV_DERN_DT_EFF = tvar_DT_EFF[i-1];
code = 1;
end;
end;
end;
run;
1 Answer 1
First, let me demonstrate how to "transpose" your data as you've shown.
I'll start with some reproducible data.
quux <- structure(list(individual = c(14418L, 14418L, 14418L, 14419L, 14419L, 14420L, 14420L, 14421L, 14421L, 14422L, 14422L, 14423L, 14423L, 14424L, 14424L, 14425L, 14425L, 14426L, 125521L, 125521L, 125521L, 999125L, 999125L, 888525L), status = c(4L, 3L, 20L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 1L, 12L, 1L, 5L, 4L, 1L, 4L, 1L), effective_on = structure(c(9093, 13215, 18628, 12324, 13525, 12324, 13525, 12324, 13525, 12324, 13525, 12324, 13525, 12324, 13525, 12324, 12704, 12324, 18262, 19118, 20368, 18294, 18933, 18716), class = "Date")), class = "data.frame", row.names = c(NA, -24L))
quux
# individual status effective_on
# 1 14418 4 1994年11月24日
# 2 14418 3 2006年03月08日
# 3 14418 20 2021年01月01日
# 4 14419 12 2003年09月29日
# 5 14419 12 2007年01月12日
# 6 14420 12 2003年09月29日
# 7 14420 12 2007年01月12日
# 8 14421 12 2003年09月29日
# 9 14421 12 2007年01月12日
# 10 14422 12 2003年09月29日
# 11 14422 12 2007年01月12日
# 12 14423 12 2003年09月29日
# 13 14423 12 2007年01月12日
# 14 14424 12 2003年09月29日
# 15 14424 12 2007年01月12日
# 16 14425 12 2003年09月29日
# 17 14425 1 2004年10月13日
# 18 14426 12 2003年09月29日
# 19 125521 1 2020年01月01日
# 20 125521 5 2022年05月06日
# 21 125521 4 2025年10月07日
# 22 999125 1 2020年02月02日
# 23 999125 4 2021年11月02日
# 24 888525 1 2021年03月30日
Assumptions:
dplyris loaded, and we'll addtidyrfor pivoting/transposing- all
effective_on"dates" are already sorted within each individual, it's trivial to fix this assumption by prependingarrange(effective_on)before the code assigningrn=
library(dplyr)
library(tidyr)
quux |>
mutate(.by = individual, rn = row_number()) |>
pivot_wider(id_cols=individual, names_from = rn, values_from = c(status, effective_on))
# # A tibble: 12 ×ばつ 7
# individual status_1 status_2 status_3 effective_on_1 effective_on_2 effective_on_3
# <int> <int> <int> <int> <date> <date> <date>
# 1 14418 4 3 20 1994年11月24日 2006年03月08日 2021年01月01日
# 2 14419 12 12 NA 2003年09月29日 2007年01月12日 NA
# 3 14420 12 12 NA 2003年09月29日 2007年01月12日 NA
# 4 14421 12 12 NA 2003年09月29日 2007年01月12日 NA
# 5 14422 12 12 NA 2003年09月29日 2007年01月12日 NA
# 6 14423 12 12 NA 2003年09月29日 2007年01月12日 NA
# 7 14424 12 12 NA 2003年09月29日 2007年01月12日 NA
# 8 14425 12 1 NA 2003年09月29日 2004年10月13日 NA
# 9 14426 12 NA NA 2003年09月29日 NA NA
# 10 125521 1 5 4 2020年01月01日 2022年05月06日 2025年10月07日
# 11 999125 1 4 NA 2020年02月02日 2021年11月02日 NA
# 12 888525 1 NA NA 2021年03月30日 NA NA
In order to force this out to 5-wide, I'll add a fake individual with 5 rows of data, filter all other individuals to be no more than 5 observations, and then remove the fake individual after the pivot. I'm using -1 for the fake individual, you will need to make sure whatever you use here is guaranteed to be not present in the real data.
quux1 <- quux |>
dplyr::rows_append(tibble(individual=-1L, effective_on=Sys.Date()+1:5)) |>
mutate(.by = individual, rn = row_number()) |>
filter(rn <= 5) |>
pivot_wider(id_cols=individual, names_from = rn, values_from = c(status, effective_on)) |>
filter(individual != -1L)
quux1
# # A tibble: 12 ×ばつ 11
# individual status_1 status_2 status_3 status_4 status_5 effective_on_1 effective_on_2 effective_on_3 effective_on_4 effective_on_5
# <int> <int> <int> <int> <int> <int> <date> <date> <date> <date> <date>
# 1 14418 4 3 20 NA NA 1994年11月24日 2006年03月08日 2021年01月01日 NA NA
# 2 14419 12 12 NA NA NA 2003年09月29日 2007年01月12日 NA NA NA
# 3 14420 12 12 NA NA NA 2003年09月29日 2007年01月12日 NA NA NA
# 4 14421 12 12 NA NA NA 2003年09月29日 2007年01月12日 NA NA NA
# 5 14422 12 12 NA NA NA 2003年09月29日 2007年01月12日 NA NA NA
# 6 14423 12 12 NA NA NA 2003年09月29日 2007年01月12日 NA NA NA
# 7 14424 12 12 NA NA NA 2003年09月29日 2007年01月12日 NA NA NA
# 8 14425 12 1 NA NA NA 2003年09月29日 2004年10月13日 NA NA NA
# 9 14426 12 NA NA NA NA 2003年09月29日 NA NA NA NA
# 10 125521 1 5 4 NA NA 2020年01月01日 2022年05月06日 2025年10月07日 NA NA
# 11 999125 1 4 NA NA NA 2020年02月02日 2021年11月02日 NA NA NA
# 12 888525 1 NA NA NA NA 2021年03月30日 NA NA NA NA
You mentioned:
comparing those dates with DT_DEB and or DT_FIN
I don't know how DT_FIN factors into this, but I'll add your logic for DT_DEB by first determining the two relevant dates/statuses, and then joining that on to the above.
quux2 <- quux |>
filter(effective_on < DT_DEB) |>
slice_max(by = individual, order_by = effective_on, n = 2) |>
arrange(desc(effective_on)) |>
reframe(.by = individual, DERN_STATUT = effective_on[1], DERN_DT_EFF = effective_on[2], AV_DERN_STATUT = status[1], AV_DERN_DT_EFF = status[2])
quux2
# individual DERN_STATUT DERN_DT_EFF AV_DERN_STATUT AV_DERN_DT_EFF
# 1 125521 2022年05月06日 2020年01月01日 5 1
# 2 999125 2021年11月02日 2020年02月02日 4 1
# 3 888525 2021年03月30日 <NA> 1 NA
# 4 14418 2021年01月01日 2006年03月08日 20 3
# 5 14419 2007年01月12日 2003年09月29日 12 12
# 6 14420 2007年01月12日 2003年09月29日 12 12
# 7 14421 2007年01月12日 2003年09月29日 12 12
# 8 14422 2007年01月12日 2003年09月29日 12 12
# 9 14423 2007年01月12日 2003年09月29日 12 12
# 10 14424 2007年01月12日 2003年09月29日 12 12
# 11 14425 2004年10月13日 2003年09月29日 1 12
# 12 14426 2003年09月29日 <NA> 12 NA
with the final join revealing:
left_join(quux1, quux2, join_by(individual))
# # A tibble: 12 ×ばつ 15
# individual status_1 status_2 status_3 status_4 status_5 effective_on_1 effective_on_2 effective_on_3 effective_on_4 effective_on_5 DERN_STATUT DERN_DT_EFF AV_DERN_STATUT AV_DERN_DT_EFF
# <int> <int> <int> <int> <int> <int> <date> <date> <date> <date> <date> <date> <date> <int> <int>
# 1 14418 4 3 20 NA NA 1994年11月24日 2006年03月08日 2021年01月01日 NA NA 2021年01月01日 2006年03月08日 20 3
# 2 14419 12 12 NA NA NA 2003年09月29日 2007年01月12日 NA NA NA 2007年01月12日 2003年09月29日 12 12
# 3 14420 12 12 NA NA NA 2003年09月29日 2007年01月12日 NA NA NA 2007年01月12日 2003年09月29日 12 12
# 4 14421 12 12 NA NA NA 2003年09月29日 2007年01月12日 NA NA NA 2007年01月12日 2003年09月29日 12 12
# 5 14422 12 12 NA NA NA 2003年09月29日 2007年01月12日 NA NA NA 2007年01月12日 2003年09月29日 12 12
# 6 14423 12 12 NA NA NA 2003年09月29日 2007年01月12日 NA NA NA 2007年01月12日 2003年09月29日 12 12
# 7 14424 12 12 NA NA NA 2003年09月29日 2007年01月12日 NA NA NA 2007年01月12日 2003年09月29日 12 12
# 8 14425 12 1 NA NA NA 2003年09月29日 2004年10月13日 NA NA NA 2004年10月13日 2003年09月29日 1 12
# 9 14426 12 NA NA NA NA 2003年09月29日 NA NA NA NA 2003年09月29日 NA 12 NA
# 10 125521 1 5 4 NA NA 2020年01月01日 2022年05月06日 2025年10月07日 NA NA 2022年05月06日 2020年01月01日 5 1
# 11 999125 1 4 NA NA NA 2020年02月02日 2021年11月02日 NA NA NA 2021年11月02日 2020年02月02日 4 1
# 12 888525 1 NA NA NA NA 2021年03月30日 NA NA NA NA 2021年03月30日 NA 1 NA
BTW, I'm using |> as a pipe, you are free to use %>% instead, it requires no changes here. (For discussion of the differences, see What are the differences between R's native pipe `|>` and the magrittr pipe `%>%`?)
for, that's where the extra argument comes from. In a pipe, the first argument defaults to what you are passing from the previous instruction on to the next one. Also, what isrow? If you are counting onrowwiseto create an object namedrow, well, it does not.dputformat? Please edit the question with the code you tried and with the output ofdput(TR_HISTO_STATUT). Or, if the data set is too big with the output ofdput(head(TR_HISTO_STATUT, 20)). And the same withSTATUT.