3
votes

Recherche dans R dans les tables de données avec la condition "IF"

J'ai deux tableaux de données. Un tableau avec les commandes des clients (il montre un identifiant client et la date de la commande lorsqu'un achat a été effectué) et un tableau avec la segmentation des clients (il montre dans quel segment un client a été classé comme dans une certaine période). souhaitez ajouter le segment de la table de données 2) en tant que nouvelle variable dans la table de données 1) mais bien sûr, seul le segment dans lequel se trouvait le client au moment de la commande.

Result <- data.table(
 customer_ID = c("A", "A"),
 order_date = c("2017-06-30", "2019-07-30"),
 segment = c(1, 3)
)
head(Result)
   customer_ID order_date segment
1:           A 2017-06-30       1
2:           A 2019-07-30       3

Voici le résultat construit manuellement que je recherche

Customer_Orders <- data.table(
 customer_ID = c("A", "A"),
 order_date = c("2017-06-30", "2019-07-30")
)
head(Customer_Orders)
  customer_ID order_date
1:           A 2017-06-30
2:           A 2018-07-30


Customer_Segmentation <- data.table(
 customer_ID = c("A", "A", "A"),
 segment = c("1", "2", "3"),
 valid_from = c("2017-01-01", "2018-01-01", "2019-01-01"),
 valid_until = c("2017-12-31", "2018-12-31", "2019-12-31")
)
head(Customer_Segmentation)
   customer_ID segment valid_from valid_until
1:           A       1  2017-01-01 2017-12-31
2:           A       2  2018-01-01 2018-12-31
3:           A       3  2019-01-01 2019-12-31

Actuellement, ma solution consiste à faire une jointure à droite pour ajouter fondamentalement tous les segments possibles à chaque ligne dans le table des commandes client, puis excluez toutes les lignes dont la date de commande ne se situe pas entre la période du segment. Cependant, comme mon ensemble de données est énorme, c'est une solution vraiment lente et lourde


3 commentaires

"2017-06-31" n'est pas une date valide. Vous pourriez vouloir dire data.frame ou tibble au lieu de data.table .


Cela semble être un cas évident pour une "jointure non équi". Recherchez ce terme avec "R data.table date" et vous devriez trouver plusieurs questions / réponses


Je n'avais pas réalisé que data.table était un package. Intéressant.


3 Réponses :


3
votes

La méthode la plus simple serait probablement d'utiliser package:

setkey(Customer_Segmentation,customer_ID,valid_from)
setkey(Customer_Orders,customer_ID,order_date)

 ans <- Customer_Segmentation[Customer_Orders,list(.valid_from=valid_from,
                                                    valid_until,order_date,segment),
                      by=.EACHI,roll=T][,`:=`(.valid_from=NULL)]

 ans


# customer_ID valid_from valid_until order_date segment
# 1:           A 2017-06-31  2017-12-31 2017-06-31       1
# 2:           A 2019-07-30  2019-12-31 2019-07-30       3

Il rejoint simplement les tables si la date tombe entre la période de temps fournie

Mais si vous insistez pour utiliser regardez ci-dessous;

library(sqldf)
sqldf("select * from Customer_Orders
               left join Customer_Segmentation
               on order_date between valid_from and valid_until
               and Customer_Orders.ID = Customer_Segmentation.ID")


# customer_ID order_date customer_ID..3 segment valid_from valid_until
# 1           A 2017-06-31              A       1 2017-01-01  2017-12-31
# 2           A 2019-07-30              A       3 2019-01-01  2019-12-31


5 commentaires

La jointure non équi serait plus simple que la jointure progressive Customer_Segmentation [Customer_Orders, on = c ("valid_from <= order_date", "valid_until> = order_date")] , car elle recrée à peu près le logique du code SQL.


@thelatemail est d'accord. N'a pas beaucoup réfléchi à la solution data.table . À votre santé.


@thelatemail: Si j'utilise votre code, je n'obtiens pas le résultat correct. J'obtiens une table avec cinq colonnes: customer_ID, segment, valid_from, valid_until, i.customer_ID. Les informations sur la date de commande, cependant, ne sont pas là


En fait, je l'ai fait maintenant, semble fonctionner: Customer_Orders [Customer_Segmentation, on =. (Customer_ID, order_date> = valid_from, order_date <= valid_until), segment: = segment]


@JenniferWeingarten, vous pouvez sélectionner en utilisant la place j au lieu de l'affectation (ce qui, à mon avis, est plus lent pour les grandes tables de données): Customer_Segmentation [Customer_Orders,. (Customer_ID, order_date, segment), on =. (Valid_from <= order_date , valid_until> = order_date, customer_ID == customer_ID)]



0
votes

Comment est-ce?

Vos données (corrigées):

# A tibble: 2 x 5
  customer_ID order_date segment valid_from valid_until
  <chr>       <date>     <chr>   <date>     <date>     
1 A           2017-06-30 1       2017-01-01 2017-12-31 
2 A           2019-07-30 3       2019-01-01 2019-12-31 

Code - les deux premières tables sont juste pour créer des dates à partir des tables initiales en utilisant lubridate . Le suivant rejoint tout.

Customer_Orders3 <- Customer_Orders_join %>% 
  filter(order_date %within% interval(valid_from, valid_until))

Ceci sélectionne les segments en fonction de l'intervalle.

Customer_Orders2 <- Customer_Orders %>% 
  mutate(order_date = ymd(order_date))

Customer_Segmentation2 <- Customer_Segmentation %>% 
  mutate(valid_from = ymd(valid_from)) %>% 
  mutate(valid_until = ymd(valid_until))

Customer_Orders_join <- full_join(Customer_Orders2, Customer_Segmentation2)

Cela produit:

library(tidyverse)
library(lubridate)

Customer_Orders <- tibble(
  customer_ID = c("A", "A"),
  order_date = c("2017-06-30", "2019-07-30"))

Customer_Segmentation <- tibble(
  customer_ID = c("A", "A", "A"),
  segment = c("1", "2", "3"),
  valid_from = c("2017-01-01", "2018-01-01", "2019-01-01"),
  valid_until = c("2017-12-31", "2018-12-31", "2019-12-31"))


0 commentaires

0
votes

Voici comment j'aborderais le problème:

Génération de données (définissant comme des vecteurs Date appropriés)

Customer_Orders[Customer_Segmentation, segment := i.segment, on = .(customer_ID==customer_ID,
                                                                    order_date>=valid_from,
                                                                    order_date<valid_until)]

print(Customer_Orders)
#   customer_ID order_date segment
#1:           A 2017-06-30       1
#2:           A 2019-07-30       3

Jointure de mise à jour non équi pour ajouter un segment

Lorsque vous utilisez la syntaxe A [B] prise en charge par data.table , il est relativement simple d'ajouter une seule colonne à partir du B à la table A d'origine en utilisant le préfixe i. pour référencer les colonnes dans B . La partie restante est juste l'instruction on , qui peut être définie comme une liste en utilisant la notation . () dans data.table avec n'importe quel nombre des conditions.

Customer_Orders <- data.table(
  customer_ID = c("A", "A"),
  order_date = as.Date(c("2017-06-30", "2019-07-30"))
)


Customer_Segmentation <- data.table(
  customer_ID = c("A", "A", "A"),
  segment = c("1", "2", "3"),
  valid_from =  as.Date(c("2017-01-01", "2018-01-01", "2019-01-01")),
  valid_until =  as.Date(c("2017-12-31", "2018-12-31", "2019-12-31"))
)


0 commentaires