2
$\begingroup$

So let's imagine I have a dataset of children. For each of them a have a bunch of characteristics (generation, gender, race, class, urban/rural, religion, bmi, number of siblings etc..) and plus the age (in months) when they did for the first the following events

  1. Learn how to ride a bike
  2. learn how to swim,
  3. starting middle school,
  4. learn how to divide with more than 2 digits
  5. have a sleepover
  6. having allowance
  7. hitting puberty
  8. owning an electronic device

My objective is that given a new kid whose characteristics (independent variables) I know (gender, race, religion etc...) being able to predict the ORDER of these events for a kid.

Here is what I tried so far (from more simple to more complex)

First Approach

For each observation, I only consider the first event. I treat it as a classification problem to predict the first event of a child. Then I see what is the most common sequence that start with that particular event and I assign that for that child.

This one obviously will be horrible, but it may have a little bit of sense if we suppose that the order of the events are strongly correlated, in this case the first event determine totally the order of the rest.

Second Approach

I have also thought this. For each kid in the dataset, you transform the age (in months) of each event in the rank of events for this specific child. For example for this particular I transform it like that: From this:

  data
    #  Gender Class Religion   ... *Bike* *Swim* *MiddleSchool* *Divides*  *Sleepover* *Allowance* *Puberty* *Device*
    #1   Male   Rich  Budhist       86      130       125           163        140       230       210        250   

Into this:

  data
    #  Gender Class Religion   ... *Bike* *Swim* *MiddleSchool* *Divides*  *Sleepover* *Allowance* *Puberty* *Device*
    #1   Male   Rich  Budhist       1        3         2            5           4           7         6        8   

And then do a regression model for each event individually that predicts the estimated rank in comparison with the rest of the events giving an specific child. The regression will give you a number between 1 and 8 (not necessarily integer) and you will have to once again,rank them from 1 to 8 (integers)

This is also a bad approach. Basically because doing each regression individually, is supposing that the events are independent, but in reality it usually obeys for patterns. For example if a child can't bike by the time he reaches middle school, it means he will bike and then swim just after the starting middle school event because it will the first thing he try at gym classes (I couldn't think of a better example)

Third Approach

Basically the same but instead of doing the regression on the rank of each event, it is directly done in the age of that event. Not sure if this is better than the last one.

Fourth Approach

The same that the last one but instead of doing the regression directly on the age, you normalize from 0 to 10 being 0 the age first event and 10 the age of the last one for the age of each event. It will be better than approach 2 because not only it will give you the rank of each event, but how close to each other are.

Fifth approach

It will basically be any of the 3 previous approach but instead of doing a regression model for each event individually, it will be collectively, having more information due to the dependence between the events.

For example, if we select the regression on the rank of each event (like in the approach 2), our target instead of being numerical will be a 8-dimension numerical vector like [1,3,2,5,4,7,6,8]

This apparently can be done throught Neural Networks or TramineR (but that is only available in R)

The problem is I can't find any information about this kind of problems because usually the ones tagged as "sequence analysis" like the DNA one are completely different, you can repeat events and it's more related with time series so I don't even know where to search. I would like to find a dataset on Kaggle for working with this type of things.

I will be extremely grateful if someone bright me a little bit with this.

$\endgroup$

2 Answers 2

2
$\begingroup$

As proposed in my answer to your previous question, a solution is to grow a regression tree of observed orders and then use a representative order of the leaf as predicted order of profiles that would be attributed to the leaf.

In the answer given to your previous question, I showed how to grow a regression tree for event sequences (the orders). I show here how, after having grown a regression tree of observed orders, you can predict an order for a given profile.

I use again the activity calendar data actcal of TraMineR. These are 12 months long sequences with the activity state each month. There are four possible activity states: A = fulltime work, B = long parttime work, C = short parttime work, D = Unemployed. For illustration, I shall consider only sequences with at least two distinct states instead of all sequences as in the other answer. Also, I derive, here, the event sequences from state sequences instead of using the timestamped event sequences data set actcal.tse.

library(TraMineR)
library(TraMineRextras) ## for seqedist

## loading actcal data (one case per line)
data(actcal)
## state sequences
actcal.seq <- seqdef(actcal[,13:24])
## to ignore state durations we take sequences
##  of distinct successive states (DSS)
actcal.dss <- seqdss(actcal.seq, with.missing = FALSE)

For this illustration we retain only sequences with at least two distinct states

sel.morethanone <- which(seqlength(actcal.dss) > 1)
actcal2 <- actcal[sel.morethanone,]
actcal2.seq <- actcal.seq[sel.morethanone,]
actcal2.dss <- actcal.dss[sel.morethanone,]

## Transforming dss sequences into event sequences 
actcal2.eseq <- seqecreate(actcal2.dss, tevent="state",
                   end.event=attr(actcal2.dss,'void'))

## assign unit cost for insertion/deletion of each event
idcost <- rep(1, length(alphabet(actcal2.eseq)))
## computing the dissimilarities between event sequences
dd <- seqedist(actcal2.eseq, idcost=idcost, vparam=.1)
dim(dd)
# [1] 370 370

Growing and plotting the tree

dtree <- disstree(dd ~ educat00 + civsta00 + age00, data=actcal2)
## Plot the tree using index plots for rendering order
gvpath <- "C:/Program Files/Graphviz"
disstreedisplay(dtree, image.data=actcal2.dss, gvpath=gvpath,
                filename="fg-event-seq-tree-I.png",
                image.fun=seqIplot, sortv="from.start",
                show.tree=TRUE)

enter image description here

Retrieving rules for assigning additional cases to the leaves

## retrieving rules defining leaf membership
dleafs <- disstreeleaf(dtree, label=TRUE)
rules <- levels(dleafs)

## Writing rules as R conditions
cleanrules <- function(rules){
  for (i in 1:length(rules)){
    ru <- rules[i]
    ru <- gsub("\\[","%in% c('", ru)
    ru <- gsub(", ","', '", ru)
    ru <- gsub("\\]","')", ru)
    rules[i] <- ru
  }
  return(rules)
}
rrules <- cleanrules(rules)

Identifying a representative order of each leaf

## Leaf membership
leaf.grp <- disstreeleaf(dtree)

## function to identify the representative of each leaf
rep.grp <- function(leaf.grp, diss, criterion="density") {
  leaf.grp <- factor(leaf.grp)
  grp.lev <- levels(leaf.grp)
  rep <- vector(length=length(grp.lev))
  #ids <- 1:length(id.grp)
  for (i in 1:length(grp.lev)){
  id.grp <- which(leaf.grp==grp.lev[i])
    rep[i] <- suppressMessages(
                    id.grp[dissrep(diss[id.grp,id.grp],
                         criterion=criterion, nrep=1)]
    )
  }
  return(rep)
}

## representative order of the leaves
rep <- rep.grp(leaf.grp, dd)
actcal2.eseq[rep]

Defining a function for predicting the leaf for a given profile

## function predicting the leaf for a given profile (case)
predictleaf <- function(case, rrules){
  age00 <- case$age00
  educat00 <- case$educat00
  civsta00 <- case$civsta00
  res <- logical(length(rrules))
  for (i in 1:length(rrules)) {
    res[i] <- eval(parse(text=rrules[i]))
  }
  which(res)
}

Once we have predicted the leaf, we use the representative of the leaf as predicted order. I illustrate with three example profiles:

## Individual who has completed a full-time vocational school, is married and aged 48:
case1 <- data.frame(educat00="full-time vocational school", civsta00="married", age00=48)
## same profile as case1 but aged 20
case2 <- data.frame(educat00="full-time vocational school", civsta00="married", age00=20)
## married, aged 60, and apprenticeship as education level.
case3 <- data.frame(educat00="apprenticeship", civsta00="married", age00=60)

## for case1
## predicted leaf
(leaf.pred <- predictleaf(case1,rrules))
## rule used
rrules[leaf.pred]
## predicted representative 
rep[leaf.pred]
## predicted order
actcal2.eseq[rep[leaf.pred]]
#[1] (D)-1-(C)-1    

## for case2
(leaf.pred <- predictleaf(case2,rrules))
rrules[leaf.pred]
rep[leaf.pred]
actcal2.eseq[rep[leaf.pred]]
#[1] (A)-1-(D)-1

## for case3
(leaf.pred <- predictleaf(case3,rrules))
rrules[leaf.pred]
rep[leaf.pred]
actcal2.eseq[rep[leaf.pred]]
#[1] (C)-1-(D)-1

In the example above, the individual do not all experiment all events and may experiment a same event several times. Therefore, sequences are of different lengths and the predicted orders do not necessarily exhibit all events. In your example, all cases experiment all events and each event only once. Then, this will of course also be the case of the predicted orders.

$\endgroup$
2
  • $\begingroup$ First of all thank you so much for you dedication in developing this techniques and giving me such a complete answer. As my knowledge in R is very limited, I'm wondering if all of this code could be easily implemented on python. $\endgroup$ Commented Aug 8, 2023 at 21:43
  • $\begingroup$ The key aspects are the computation of the pairwise dissimilarities between sequences and the growing of the regression tree from a dissimilarity matrix. These are both partly coded in C++ in TraMineR. Although it should be possible to implement that in python, it would require a lot of work. The current version of TraMineR is the result of over 15 years development. $\endgroup$
    – Gilbert
    Commented Aug 9, 2023 at 7:11
0
$\begingroup$

I really think that your research question calls for a sequence analysis approach. Given your post it seems that you have little prior knowledge and hence have to read some introductory material. I can recommend the TraMineR user guide:

Gabadinho, A., G. Ritschard, M. Studer and N. S. Müller, Mining sequence data in R with the TraMineR package: A user's guide, University of Geneva, 2009. (http://mephisto.unige.ch/pub/TraMineR/doc/TraMineR-Users-Guide.pdf)

If you prefer to work in Stata instead of R you could have a look at:

Brzinsky-Fay, C., Kohler, U., & Luniak, M. (2006). Sequence Analysis with Stata. The Stata Journal, 6(4), 435–460. https://doi.org/10.1177/1536867X0600600401

A more comprehensive introduction to SA is provided in the book I wrote together with Emanuela Struffolino:

Raab, M. & Struffolino, E. (2022). Sequence Analysis. Thousand Oaks, CA: Sage.

The book's companion webpage (https://sa-book.github.io/) illustrates how to replicate the results shown in the book using R and TraMineR.

Given your example, the "classical" sequence analysis approach would

(1) start with defining your sequences,

(2) comparing them by computing a pairwise dissimilarity matrix,

(3) conducting a cluster analysis using this matrix

(4) predicting cluster membership with variables measured prior to the onset of your sequences by estimating a multinomial logistic regression.

How you define the sequences depends on the available information. If you observe all children for the same amount of time (say from age 5 to 15), you could create sequences of equal length that not only include information on the order of events but also on the timing - which might be quite interesting from a substantive point of view. Alternatively, sequence analysis would also allow for discarding timing information by exclusively focusing on the order of events (as outlined above). In the latter case, you would work with sequences of length eight, assuming that every child experiences every event.

Response to comment

If you want to avoid the clustering step, you could consider a discrepancy analysis instead. Within the discrepancy framework, you could analyze the factors (e.g., gender, race, religion) that "explain" the variance in the discrepancy of your sequences without lumping the sequences into clusters. The approach is introduced in

Studer, M., Ritschard, G., Gabadinho, A., & Müller, N. S. (2011). Discrepancy Analysis of State Sequences. Sociological Methods & Research, 40(3), 471–510. https://doi.org/10.1177/0049124111415372

(It's also covered in chapter 6 of our book, of course)

Particularly the regression tree approach might be interesting in your case.

$\endgroup$
1
  • $\begingroup$ I think I understood what you propose but the think is that I want an exact sequence for each kid, not assigning it a bunch of similar sequences, that it is as far as I know, what clusterization do. $\endgroup$ Commented Aug 8, 2023 at 1:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.