J'ai le tableau de données suivant:
while(any(is.na(dt))){
dt[, `:=` (
EO_3 = calc_EO_3(EO_1, EO_2),
EO_1 = ifelse(ID == "ID_001", EO_1, calc_EO_1(EO_1, EO_2)),
EO_2 = ifelse(ID == "ID_001", EO_2, calc_EO_2(EO_1, EO_2, EO_3))
)]
}
et j'essaie d'effectuer des opérations par ligne, qui dépendent parfois des données des lignes précédentes. Plus précisément:
ID | EO_1 | EO_2 | EO_3 | GROUP ID_001 | 0.50000000 | 1.20000000 | 0.60000000 | A ID_002 | 0.60000000 | 0.43200000 | 0.25920000 | A ID_003 | 0.25920000 | 0.02902376 | 0.00752296 | A ID_004 | 0.00752296 | 0.00000164 | 0.00000001 | A ID_001 | 0.40000000 | 2.50000000 | 1.00000000 | B ID_002 | 1.00000000 | 2.50000000 | 2.50000000 | B ID_003 | 2.50000000 | 15.62500000 | 39.06250000 | B ID_004 | 39.06250000 | 23841.8580000 | 931322.57810000 | B
Le dernier devrait être calculé à partir de la première ligne car il dépend des autres champs (cela devrait être facile) et, après cela, des trois les opérations devraient avoir lieu consécutivement et par ligne.
Le plus proche que j'ai été a été le suivant:
ID | EO_1 | EO_2 | EO_3 | GROUP ID_001 | 0.5 | 1.2 | 0.6 | A ID_002 | | | | A ID_003 | | | | A ID_004 | | | | A ID_001 | 0.4 | 2.5 | 1.0 | B ID_002 | | | | B ID_003 | | | | B ID_004 | | | | B
mais il ne calcule que le première ligne correctement:
first_row_bygroup_index <- dt[, .I[1], by = GROUP]$V1
dt[first_row_bygroup_index,
EO_3 := calc_EO_3(EO_1, EO_2)
]
dt[!first_row_bygroup_index,
`:=` (
EO_1 = calc_EO_1(EO_1, EO_2),
EO_2 = calc_EO_2(EO_1, EO_2, EO_3),
EO_3 = calc_EO_3(EO_1, EO_2)
),
by = row.names(dt[!first_row_bygroup_index])]
Étant ces espaces NA.
Je ne pense pas que je suis trop loin de la solution, mais je suis pas en mesure de trouver un moyen de le faire fonctionner. Le problème est que je ne peux pas effectuer d'opérations dans des sous-ensembles de lignes en utilisant des lignes extérieures au sous-ensemble.
MODIFIER J'ai manqué le résultat attendu:
calc_EO_1 <- function(
EO_1,
EO_2
){
EO_1 <- shift(EO_1, type = "lag") * shift(EO_2, type = "lag")
return(EO_1)
}
calc_EO_2 <- function(
EO_1,
EO_2,
EO_3
){
EO_2 <- EO_1 * shift(EO_2, type = "lag") * shift(EO_3, type = "lag")
return(EO_2)
}
calc_EO_3 <- function(
EO_1,
EO_2
){
EO_3 <- EO_1 * EO_2
return(EO_3)
}
NOUVELLE MODIFICATION J'ai trouvé l'extrait de code suivant, mais je préfère attendre un peu pour voir si quelqu'un peut trouver une solution plus efficace que celle-ci:
dt <- fread("
ID | EO_1 | EO_2 | EO_3 | GROUP
ID_001 | 0.5 | 1.2 | | A
ID_002 | | | | A
ID_003 | | | | A
ID_004 | | | | A
ID_001 | 0.4 | 2.5 | | B
ID_002 | | | | B
ID_003 | | | | B
ID_004 | | | | B
",
sep = "|",
colClasses = c("character", "numeric", "numeric", "numeric", "character"))
J'ai trouvé une solution de dplyr similaire, avec ce correctif laid while-loop également. La clé serait de trouver un moyen de faire un calcul par ligne qui pourrait obtenir des informations de la ligne précédente, même si cette ligne avant serait en dehors du sous-ensemble sélectionné. J'espère que quelqu'un pourra améliorer cela, alors j'attendrai un peu avant de le marquer comme solution.
3 Réponses :
S'agit-il du type de données auquel vous vous attendez du produit final?
go <- function(x, y, n) {
z <- x * y
for (i in 1:(n - 1)) {
x <- c(x[1] * y[1], x)
y <- c(x[1] * y[1] * z[1], y)
z <- x * y
}
data.table(EO_1 = x, EO_2 = y, EO_3 = z)[.N:1][, lapply(.SD, round, 8)]
}
go(.5, 1.2, 4)
EO_1 EO_2 EO_3
1: 0.50000000 1.20000000 0.60000000
2: 0.60000000 0.43200000 0.25920000
3: 0.25920000 0.02902376 0.00752296
4: 0.00752296 0.00000164 0.00000001
Oh oui. Mon erreur, je vais mettre à jour la question avec le résultat attendu. Ne vous inquiétez pas des valeurs réelles, il s'agit d'un cas simplifié avec des entrées aléatoires, la vraie chose est bien plus grande, comme d'habitude. Comment pourrais-je calculer le tout à partir de l'entrée donnée?
J'ai trouvé une solution, même si elle est inefficace et laide. Pensez-vous pouvoir l'améliorer?
Voici une autre approche possible:
ID EO_1 EO_2 EO_3 GROUP 1: ID_001 0.50000000 1.200000e+00 6.000000e-01 A 2: ID_002 0.60000000 4.320000e-01 2.592000e-01 A 3: ID_003 0.25920000 2.902376e-02 7.522960e-03 A 4: ID_004 0.00752296 1.642598e-06 1.235720e-08 A 5: ID_001 0.40000000 2.500000e+00 1.000000e+00 B 6: ID_002 1.00000000 2.500000e+00 2.500000e+00 B 7: ID_003 2.50000000 1.562500e+01 3.906250e+01 B 8: ID_004 39.06250000 2.384186e+04 9.313226e+05 B
sortie:
dt[!is.na(EO_1), EO_3 := EO_1 * EO_2, by=.(GROUP)]
dt[ID!="ID_001", c("EO_1", "EO_2", "EO_3") :=
dt[,
{
eo1 <- EO_1[1L]; eo2 <- EO_2[1L]; eo3 <- EO_3[1L]
.SD[ID!="ID_001",
{
eo1 <- eo1 * eo2
eo2 <- eo1 * eo2 * eo3
eo3 <- eo1 * eo2
.(eo1, eo2, eo3)
},
by=.(ID)]
},
by=.(GROUP)][, -1L:-2L]
]
Question délicate! J'ai essayé d'utiliser nest de dplyr et d'appliquer une fonction de costum.
ID EO_1 EO_2 EO_3 GROUP 1 ID_001 0.50000000 1.20000000 0.60000000 A 2 ID_002 0.60000000 0.43200000 0.25920000 A 3 ID_003 0.25920000 0.02902376 0.00752296 A 4 ID_004 0.00752296 0.00000164 0.00000001 A 5 ID_001 0.40000000 2.50000000 1.00000000 B 6 ID_002 1.00000000 2.50000000 2.50000000 B 7 ID_003 2.50000000 15.62500000 39.06250000 B 8 ID_004 39.06250000 23841.85791016 931322.57461548 B
vous donnant
options("scipen"=999, "digits"=8)
library(tidyverse)
# Custom function
logic <- function(.df){
for(i in 2:nrow(.df)){
.df[i, "EO_1"] <- .df[i-1, "EO_1"] * .df[i-1, "EO_2"]
.df[i, "EO_2"] <- .df[i, "EO_1"] * .df[i-1, "EO_2"] * .df[i-1, "EO_3"]
.df[i, "EO_3"] <- .df[i, "EO_1"] * .df[i, "EO_2"]
}
.df
}
# Answers the question
dt <- dt %>%
mutate(EO_3 = EO_1 * EO_2) %>%
nest(-GROUP) %>%
mutate(data = map(data, ~logic(.))) %>%
unnest()
# Fixing nice output
dt %>%
mutate_at(vars(contains("EO_")), ~round(., 8)) %>%
select(-GROUP, everything(), GROUP) %>%
as.data.frame()