repeter un bloc de lignes à la suite d'une valeur et selon des conditions

Postez ici vos questions, réponses, commentaires ou suggestions - Les sujets seront ultérieurement répartis dans les archives par les modérateurs

Modérateur : Groupe des modérateurs

alex josé
Messages : 11
Enregistré le : 29 Déc 2019, 03:57

repeter un bloc de lignes à la suite d'une valeur et selon des conditions

Messagepar alex josé » 11 Fév 2020, 15:56

Salut à tou.t.e.s,
je me casse la tête avec une repetition de lignes avec déplacement à intervalle variable, sans réelle suite.
j'ai tenté sur une plus petite echelle la repetition en utilisant rep et lead mais c'est bien difficile quand je me retrouve avec plusieurs dizaines de lignes et pire dans plusieurs millions de lignes.
je m'en remets à vous pour une explication et/ou une orientation. Ce que je souhaite faire c'est une repetition de plusieurs lignes suivant la valeur d'une colonne toute en plaçant les valeurs à repeter à la suite d'une autre cellule. Tout ceci en restant dans la même colonne.

Pour etre plus precis voici mon dataframe en entrée (input) et ce que je souhaite en sortie (output)

input <- tibble( enti = c("650", "651", "652", "653", "650", "650", "652", "654", "650", "650", "650", "670", "650", "650", "650", "650", "657", "658", "659"),
mont = c("00", "47", "45", "48", "01", "00", "54", "44", "02", "04", "00", "44", "01", "04", "06", "00", "35", "38", "39"))

/!\ la condition, je la réalise sur sur la variable enti et mont simultanément

output <- tibble( enti = c("650", "651", "652", "653", "650", "651", "652", "653", "650", "652", "654", "650", "652", "654", "650", "652", "654", "650", "670",
"650", "670", "650", "670", "650", "670", "650", "657", "658", "659"),
mont = c("00", "47", "45", "48", "01", "47", "45", "48", "00", "54", "44", "02", "54", "44", "04", "54", "44", "00", "44",
"01", "44", "04", "44", "06", "44", "00", "35", "38", "39"))

le filtre porte sur les modalités de la variable "enti" correspondant à "650" et la modalité "00". si la modalité suivante directement "00", lorsque enti vaut
"650" est "01" alors je repète les lignes qui suivent la ligne précédente: pour le premier cas, ce sont les lignes où se trouvent les valeurs "651", "652", "653" à la suite directe de
la variable enti où la modalité est "650" et la variable mont egal à "01". Je reproduis le même scénario jusqu'à ce que je me retrouve
de nouveau sur la simultanéité "650" et "00". Pour le dire autrement, je repete tant que j'ai
entite =="650" et mont == "00" puis entite =="650" et mont %in% ("01", "02", "04", "06") ou
entite =="650" et mont == "00" puis entite =="650" et mont %in% ("01", "02", "04", "06") suivi de entite =="650" et mont %in% ("02", "04", "06") .

Merci par avance pour vo.tre.s contribution.s

Pierre-Yves Berrard
Messages : 1029
Enregistré le : 12 Jan 2016, 23:30

Re: repeter un bloc de lignes à la suite d'une valeur et selon des conditions

Messagepar Pierre-Yves Berrard » 11 Fév 2020, 21:47

Bonjour,

Pas évident (donc intéressant).

Une première étape serait peut-être d'isoler les séquences à copier :

Code : Tout sélectionner

pas_650 <- input$enti != "650"

r <- rle(pas_650)
a_copier_long <- r$lengths[r$values]

sequences_a_copier <-
  split(
    input[pas_650, ],
    rep(seq(a_copier_long), a_copier_long)
  )

Avec l'idée de recombiner ensuite ces briques de base.
PY

alex josé
Messages : 11
Enregistré le : 29 Déc 2019, 03:57

Re: repeter un bloc de lignes à la suite d'une valeur et selon des conditions

Messagepar alex josé » 12 Fév 2020, 02:54

Merci à vous pour l'approche.
J'essaie de comprendre, tenterai de l'appliquer puis reviendrai vers vous pour vous dire ce qu'e j'obtiens.
Bonne journée déjà.

alex josé
Messages : 11
Enregistré le : 29 Déc 2019, 03:57

Re: repeter un bloc de lignes à la suite d'une valeur et selon des conditions

Messagepar alex josé » 12 Fév 2020, 16:03

salut @PY,

n'avez-vous pas un indice pour la suite ?
Je n'y arrive toujours pas à mes fins.

François Bonnot
Messages : 537
Enregistré le : 10 Nov 2004, 15:19
Contact :

Re: repeter un bloc de lignes à la suite d'une valeur et selon des conditions

Messagepar François Bonnot » 13 Fév 2020, 08:21

Bonjour,
Une suggestion :

Code : Tout sélectionner

input.s <- split(input,cumsum(input$enti==650))
for (i in 1:length(input.s)) {
    x <- input.s[[i]]
    if (x$mont[1]=="00") serie <- x[-1,]
    else input.s[[i]] <- rbind(x,serie)
}
do.call(rbind,input.s)
François

alex josé
Messages : 11
Enregistré le : 29 Déc 2019, 03:57

Re: repeter un bloc de lignes à la suite d'une valeur et selon des conditions

Messagepar alex josé » 13 Fév 2020, 17:07

merci @FB
ça marche pour mon exemple.
sauf que dans mes données en réalité, la position de 650 ou 00 n'est pas toujours au debut de mes données.
pour le dire autrement c'est variable.
pour le moment, je vais me dépatouiller avec ce code et revient vers vous en cas de blocage.
bonne soirée à vous

François Bonnot
Messages : 537
Enregistré le : 10 Nov 2004, 15:19
Contact :

Re: repeter un bloc de lignes à la suite d'une valeur et selon des conditions

Messagepar François Bonnot » 14 Fév 2020, 07:19

dans mes données en réalité, la position de 650 ou 00 n'est pas toujours au debut

Il suffit alors d'insérer la ligne serie <- NULL avant la boucle.
François

alex josé
Messages : 11
Enregistré le : 29 Déc 2019, 03:57

Re: repeter un bloc de lignes à la suite d'une valeur et selon des conditions

Messagepar alex josé » 15 Fév 2020, 18:51

En inscrivant NULL, je n'avais pas le resultat attendu.
De fait, ayant compris votre code, j'ai fait quelques modifications. Par exemple, j'ai fait un filtre pour donner une position qui ne changera pas à 650. Au lieu de mettre NULL, j'ai mis -1 comme valeur à attribuer à serie. Quant à la premiere valeur de la boucle for, j'ai laissé 1.

En conséquence, je veux signaler que le problème est résolu.
Merci à la communauté et en particulier à @FrançoisBonnot & @PY (j'explore toujours votre voie).

Une question (à deux volets) reste en suspens, quel(s) lien(s) et/ou livre(s) me conseilleriez-vous pour :
-maitriser les boucles?
-atteindre les 3/4 de vos acquis (@FrançoisBonnot & @PY.) sur R d'ici la fin de l'année?

En vous souhaitant, un agréable week-end !!

Pierre-Yves Berrard
Messages : 1029
Enregistré le : 12 Jan 2016, 23:30

Re: repeter un bloc de lignes à la suite d'une valeur et selon des conditions

Messagepar Pierre-Yves Berrard » 16 Fév 2020, 20:02

alex josé a écrit :@PY (j'explore toujours votre voie).

Pas vraiment nécessaire, c'est juste la même idée que celle de François mais plus poussive.
PY

alex josé
Messages : 11
Enregistré le : 29 Déc 2019, 03:57

Re: repeter un bloc de lignes à la suite d'une valeur et selon des conditions

Messagepar alex josé » 19 Fév 2020, 11:25

Bonjour à tou.t.e.s

@François Bonnot, si je reviens sur un probleme deja resolu, d'abord désolé; ensuite que c'est qu'il y a une anomalie qui s'est produite.
Je me suis aperçu de quelques anomalies dans mes traitements et en remontant étape par étape, il se pourrait que le code que je devais appliquer a été mal fait de ma part (ci-dessous le bout de code qui me parait être à l'origine du pbqui suit). j'ai un melange qui s'opere à partir d'un certain niveau dans mes données.
En effet, en generant mon code, je m’aperçois qu'une ligne apparaît hasardeusement entre deux lignes alors que ce n'etait pas le
cas avant l'application de la boucle. par exemple :

avant la boucle apres la boucle (puis un filtre) ce que je souhaitais avoir àpres mon filtre
300 650 300
358 300 650
650 ========== >>>> 651 ==========>>>> 651
652 652 653
653

pour rappel ma question est traitée ici : viewtopic.php?f=3&t=9884
et le script que je viens une nouvelle fois d'appliquer :

input.s <- split(input,cumsum(input$enti==650))
for (i in 1:length(input.s)) {
x <- input.s[[i]]
if (x$mont[1]=="00") serie <- x[-1,]
else input.s[[i]] <- rbind(x,serie)
}
do.call(rbind,input.s)

consideriez-vous qu'une reproduction malveillante puisse se réaliser à la suite d'une boucle hasardeusement ?

François Bonnot
Messages : 537
Enregistré le : 10 Nov 2004, 15:19
Contact :

Re: repeter un bloc de lignes à la suite d'une valeur et selon des conditions

Messagepar François Bonnot » 19 Fév 2020, 12:54

Bonjour,
Je ne comprends pas bien la question. Il faudrait communiquer quelques lignes de input qui déclenchent l'anomalie, au moyen de a fonction dput():
viewtopic.php?f=1&t=3302
ainsi qu'un code reproductible appliqué à ces lignes, en signalant précisément quelle ligne de la sortie est anormale.
François

alex josé
Messages : 11
Enregistré le : 29 Déc 2019, 03:57

Re: repeter un bloc de lignes à la suite d'une valeur et selon des conditions

Messagepar alex josé » 20 Fév 2020, 14:15

Bonjour à tou.t.e.s
@François Bonnot
dput(dataframe) me renvoie dans la console mon jeu de données, j'ai choisi de vous présenter quatorze lignes représentées par la table test3 pour ne pas saturer votre écran.

library("tidyr")
test3 <- tibble(v1 = c("1000102771077 ", "200027298CPS*SV310153 20171025201710", "40004000351535100 0001001 00000000",
"4059997210271250 0021", "40799201709282017092812397112", "411999701001610613 ", "40004000351535100 0007001 00000000",
"200027274CPS*SV310055 20171001201709", "40004000111035100 0001001 00000000", "4059997110275200 0121",
"40799201709292017092970197712 ", "4109997110275200 012100030521223 ", "40004000111035100 0007001 00000000", "40004000111035100 0007001 00000000"),
v2 = c("100", "200", "400", "405", "407", "411", "400", "200", "400", "405", "407", "410", "400", "400"),
v3 = c(0, 0, "00", 0, 0, 0, "05", 0, "00", 0, 0, 0, "01", "05"))

test3_corr <- split(test3,cumsum(test3$v2 == "400"))

serie <- NULL

for (i in 1:length(test3_corr)) {
x <- test3_corr[[i]]
if (x$v3[1]=="00") serie <- x[-1,]
else test3_corr[[i]] <- rbind(x, serie)
}

table3_corr <- do.call(rbind, test3_corr)

# en regardant la sortie, je me rends compte d'une anomalie entre la ligne 7 et la ligne 9 de table3_corr comparativement à la structure de test3.
# effectivement, la ligne 8 de table3_corr (avec v2=200) apparait entre les 400 et 405 (ici, cette anomalie est visible une fois). Mais sur ma table
# ca cas est perceptible plusieurs fois. Ce qui ne devrait pas être le cas. 200 est soit avant 400, soit après 400. Lorsqu'il est juste apres 400, il ne
# peut avoir à sa suite (ie consecutivement) une 405 ou une 406. Ce que je souhaitais c'est la sortie test4 suivante:
test4 <- tibble(v1 = c("1000102771077 ", "200027298CPS*SV310153 20171025201710", "40004000351535100 0001001 00000000", "4059997210271250 0021", "40799201709282017092812397112",
"411999701001610613 ", "40004000351535100 0007001 00000000", "4059997210271250 0021", "40799201709282017092812397112", "411999701001610613 ", "200027274CPS*SV310055 20171001201709",
"40004000111035100 0001001 00000000", "4059997110275200 0121", "40799201709292017092970197712 ", "4109997110275200 012100030521223 ", "40004000111035100 0007001 00000000",
"4059997110275200 0121", "40799201709292017092970197712 ", "4109997110275200 012100030521223 ", "40004000111035100 0007001 00000000",
"4059997110275200 0121", "40799201709292017092970197712 ", "4109997110275200 012100030521223 "),
v2 = c("100", "200", "400", "405", "407", "411", "400", "405", "407", "411", "200", "400", "405", "407", "410", "400", "405", "407", "410", "400", "405", "407", "410" ),
v3 = c(0, 0, "00", 0, 0, 0, "05", 0, 0, 0, 0, "00", 0, 0, 0, "01", 0, 0, 0, "05", 0, 0, 0))

rm(test3, test3_corr, table3_corr, test4)

François Bonnot
Messages : 537
Enregistré le : 10 Nov 2004, 15:19
Contact :

Re: repeter un bloc de lignes à la suite d'une valeur et selon des conditions

Messagepar François Bonnot » 20 Fév 2020, 17:12

Bonjour,
Le problème vient de ce que l'énoncé était incomplet et laissait supposer (d'après input) que les lignes qui déclenchent la répétition ne sont jamais suivies de lignes à conserver (contrairement au dernier exemple).
Le code suivant devrait fonctionner:

Code : Tout sélectionner

test3_corr <- split(test3,cumsum(test3$v2 == "400"))
serie <- NULL
for (i in 1:length(test3_corr)) {
    x <- test3_corr[[i]]
    if (x$v3[1]=="00" && x$v2[1]=="400" ) serie <- x[-1,]
    else test3_corr[[i]] <- rbind(x[1,],serie,x[-1,])
}
table3_corr <- do.call(rbind, test3_corr)
François

alex josé
Messages : 11
Enregistré le : 29 Déc 2019, 03:57

RESOLU: repeter un bloc de lignes à la suite d'une valeur et selon des conditions

Messagepar alex josé » 21 Fév 2020, 15:33

Merci @François Bonnot
Problème résolu.


Retourner vers « Questions en cours »

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 1 invité