A alegria inigualável de uniões não-equi

cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br

[ad_1]

[This article was first published on R on Tea & Stats, and kindly contributed to R-bloggers]. (Você pode relatar problemas sobre o conteúdo desta página aqui)


Quer compartilhar seu conteúdo em R-bloggers? clique aqui se você tiver um blog, ou aqui se não tiver.

Uma tarefa comum na análise de dados é fundir ou Junte-se duas tabelas de acordo com compartilhada chaves ou valores. A operação talvez seja mais comumente associada a bancos de dados relacionais e linguagem de consulta estruturada (SQL), mas é igualmente útil em R com quadros de dados.

A maioria das junções são equi-joins, correspondendo linhas de acordo com duas colunas com valores exatamente iguais. Estes são fáceis de executar em R usando a base merge() função, os vários join() funções em dplyr e a X[i] sintaxe de Tabela de dados.

Mas às vezes precisamos junções não-equi ou ( theta )-joins, onde a condição de correspondência é um intervalo ou um conjunto de desigualdades. Outras situações exigem um junção rolante, usado para vincular registros de acordo com sua proximidade em uma sequência de tempo.

Como você executa junções não equi e junções rolantes em R?

Exemplo motivador

Um famoso YouTuber está testando uma nova estratégia de marketing, promovendo vídeos específicos nas redes sociais. Eles coletam contagens de visualizações diárias de vídeos antigos e desejam resumir essas contagens nos dias seguintes a cada promoção.

As mesas promos e views são como segue. Os dados abrangem um período de duas semanas, mas para certos dias e certos vídeos, faltam as contagens de visualizações.

UMA 01-04-2020
UMA 07-04-2020
B 03-04-2020
B 08-04-2020
C 03-04-2020
UMA 01-04-2020 992
UMA 02-04-2020 3304
UMA 03-04-2020 1417
UMA 04-04-2020 191
UMA 05-04-2020 2366
UMA 06-04-2020 7318
UMA 07-04-2020 1570
UMA 08-04-2020 2051
UMA 09-04-2020 5958
UMA 10-04-2020 3574
UMA 11/04/2020 6724
UMA 12-04-2020 12043
UMA 13/04/2020 481
UMA 14-04-2020 286
B 01-04-2020 6270
B 02-04-2020 1549
B 03-04-2020 2376
B 04-04-2020 3111
B 05-04-2020 6228
B 06-04-2020 1852
B 07-04-2020 24314
B 08-04-2020 3329
B 09-04-2020 24980
B 10-04-2020 1118
B 11/04/2020 6057
B 14-04-2020 1400
C 01-04-2020 1156
C 02-04-2020 6435
C 03-04-2020 2847
C 04-04-2020 15093
C 05-04-2020 2488
C 06-04-2020 1773
C 07-04-2020 8782
C 08-04-2020 3687
C 11/04/2020 1963
C 12-04-2020 9510
C 13/04/2020 3891
C 14-04-2020 3282

Qual é a média de visualizações dos vídeos nos três dias imediatamente após as promoções desses vídeos?

Vou mostrar como você pode realizar essa tarefa usando junções não-equi ou junções rolantes em R.

Leia Também  U é para truque útil

Crossing + filtro com dplyr

O pacote dplyr não tem função para unir em nada além de uma relação de igualdade. No entanto, você pode obter os mesmos resultados (possivelmente com menos eficiência) usando uma junção externa ou produto cartesiano, seguido por uma operação de filtragem.

library(dplyr)
views %>%
  # Crossing
  full_join(promos) %>%
  # Filter
  filter(view_date >= promo_date,
         view_date %
  # Aggregate
  group_by(video) %>%
  summarise(mean(views), sd(views), `n days` = n())
UMA 2382 1832 8
B 6131 7836 8
C 5550 6377 4

Também seria possível comparar dias promovidos com dias não promovidos para cada vídeo, seja criando um indicador binário (em vez de um filtro) ou reunindo a tabela com o conjunto de dados original após a etapa de filtro.

Junções não equi com sqldf

O sqldf pacote permite consultar quadros de dados R com SQL, como se você estivesse trabalhando com um banco de dados relacional. O resultado da consulta é outro quadro de dados e o desempenho às vezes é melhor do que funções R equivalentes.

library(sqldf)
sqldf('SELECT v.video, view_date, views
       FROM views v
       JOIN promos p
       ON v.video = p.video AND
          view_date BETWEEN promo_date AND promo_date + 3'
      ) %>%
  group_by(video) %>%
  summarise(mean(views), sd(views), `n days` = n())
UMA 2382 1832 8
B 6131 7836 8
C 5550 6377 4

A etapa de agregação também pode ser escrita em SQL, mas faz sentido usar SQL apenas onde for absolutamente necessário e usar funções R nativas para todo o resto.

Ter acesso a essa funcionalidade é muito poderoso, mas tem a desvantagem óbvia de que você precisa aprender um pouco de SQL para entender a sintaxe.

Non-equi joins with data.table

O pacote de manipulação de dados de alto desempenho Tabela de dados agora (a partir de v1.9.8) suporta junções não-equi.

Junções não equi são possíveis com o X[i] mesclando sintaxe e o on argumento. É um pouco menos flexível do que o SQL equivalente, porque você não pode simplesmente escrever promo_date + 3 na desigualdade: em vez disso, precisa ser uma coluna explícita na tabela. Você também não pode usar o infixo %between% operador, então duas desigualdades devem ser feitas em seu lugar. Caso contrário, a sintaxe é semelhante. Como no SQL, um prefixo é usado para desambiguar os nomes das colunas: aqui está x.name.

library(data.table)
setDT(views)
setDT(promos)[, promo_end := promo_date + 3]
UMA 01-04-2020 04-04-2020
UMA 07-04-2020 10-04-2020
B 03-04-2020 06-04-2020
B 08-04-2020 11/04/2020
C 03-04-2020 06-04-2020
Visualizações[promos,
      .(video, views, x.view_date),
      # Non equi join:
      on = .(video,
             view_date >= promo_date,
             view_date 
A 2382 1832 8
B 6131 7836 8
C 5550 6377 4

Rolling joins with data.table

This particular example, since it involves a time variable, is even simpler using a rolling join.
The concept is a bit confusing, but essentially it attributes records in one table with the most recent preceding records in the second table.
You can read more about rolling joins in this blog post by Robert Norberg.

Leia Também  Preconceito de colisor, ou: as gostosas são escuras e se beijam feio?

When performing rolling joins in data.table, one of the joining time columns gets dropped, which can make it hard to identify your records if they don’t have an explicit ID.
To mitigate this, we will copy each date column to the name join_date and join on that.

cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br
views[, join_date := view_date]
promos[, join_date := promo_date]

setkey (visualizações, vídeo, join_date) setkey (promos, vídeo, join_date) promoções[views, roll = TRUE]
UMA 01-04-2020 01-04-2020 01-04-2020 992
UMA 01-04-2020 02-04-2020 02-04-2020 3304
UMA 01-04-2020 03-04-2020 03-04-2020 1417
UMA 01-04-2020 04-04-2020 04-04-2020 191
UMA 01-04-2020 05-04-2020 05-04-2020 2366
UMA 01-04-2020 06-04-2020 06-04-2020 7318
UMA 07-04-2020 07-04-2020 07-04-2020 1570
UMA 07-04-2020 08-04-2020 08-04-2020 2051
UMA 07-04-2020 09-04-2020 09-04-2020 5958
UMA 07-04-2020 10-04-2020 10-04-2020 3574
UMA 07-04-2020 11/04/2020 11/04/2020 6724
UMA 07-04-2020 12-04-2020 12-04-2020 12043
UMA 07-04-2020 13/04/2020 13/04/2020 481
UMA 07-04-2020 14-04-2020 14-04-2020 286
B N / D 01-04-2020 01-04-2020 6270
B N / D 02-04-2020 02-04-2020 1549
B 03-04-2020 03-04-2020 03-04-2020 2376
B 03-04-2020 04-04-2020 04-04-2020 3111
B 03-04-2020 05-04-2020 05-04-2020 6228
B 03-04-2020 06-04-2020 06-04-2020 1852
B 03-04-2020 07-04-2020 07-04-2020 24314
B 08-04-2020 08-04-2020 08-04-2020 3329
B 08-04-2020 09-04-2020 09-04-2020 24980
B 08-04-2020 10-04-2020 10-04-2020 1118
B 08-04-2020 11/04/2020 11/04/2020 6057
B 08-04-2020 14-04-2020 14-04-2020 1400
C N / D 01-04-2020 01-04-2020 1156
C N / D 02-04-2020 02-04-2020 6435
C 03-04-2020 03-04-2020 03-04-2020 2847
C 03-04-2020 04-04-2020 04-04-2020 15093
C 03-04-2020 05-04-2020 05-04-2020 2488
C 03-04-2020 06-04-2020 06-04-2020 1773
C 03-04-2020 07-04-2020 07-04-2020 8782
C 03-04-2020 08-04-2020 08-04-2020 3687
C 03-04-2020 11/04/2020 11/04/2020 1963
C 03-04-2020 12-04-2020 12-04-2020 9510
C 03-04-2020 13/04/2020 13/04/2020 3891
C 03-04-2020 14-04-2020 14-04-2020 3282

A sintaxe promos[views, roll=TRUE] significa “qual promoção precede imediatamente cada data de exibição?” Por outro lado, views[promos, roll=TRUE] significa “quais datas de exibição imediatamente precedem cada promoção?”

Neste caso, queremos algo fechar para o primeiro, mas estamos interessados ​​apenas em promoções nos últimos 3 dias, ao passo que, por padrão, ele se estenderá para as profundezas do tempo procurando pela última, independentemente de há quanto tempo.

Mudando roll = TRUE para roll = 3 a junção não corresponderá quando o join_date difere em mais de três dias entre as duas tabelas. Se quiséssemos ir na direção oposta no tempo, poderíamos usar roll = -Inf para pesquisar a tempo para futuras promoções, e roll = -3 para apenas aqueles nos três dias seguintes.

promos[views, roll = 3]
UMA 01-04-2020 01-04-2020 01-04-2020 992
UMA 01-04-2020 02-04-2020 02-04-2020 3304
UMA 01-04-2020 03-04-2020 03-04-2020 1417
UMA 01-04-2020 04-04-2020 04-04-2020 191
UMA N / D 05-04-2020 05-04-2020 2366
UMA N / D 06-04-2020 06-04-2020 7318
UMA 07-04-2020 07-04-2020 07-04-2020 1570
UMA 07-04-2020 08-04-2020 08-04-2020 2051
UMA 07-04-2020 09-04-2020 09-04-2020 5958
UMA 07-04-2020 10-04-2020 10-04-2020 3574
UMA N / D 11/04/2020 11/04/2020 6724
UMA N / D 12-04-2020 12-04-2020 12043
UMA N / D 13/04/2020 13/04/2020 481
UMA N / D 14-04-2020 14-04-2020 286
B N / D 01-04-2020 01-04-2020 6270
B N / D 02-04-2020 02-04-2020 1549
B 03-04-2020 03-04-2020 03-04-2020 2376
B 03-04-2020 04-04-2020 04-04-2020 3111
B 03-04-2020 05-04-2020 05-04-2020 6228
B 03-04-2020 06-04-2020 06-04-2020 1852
B N / D 07-04-2020 07-04-2020 24314
B 08-04-2020 08-04-2020 08-04-2020 3329
B 08-04-2020 09-04-2020 09-04-2020 24980
B 08-04-2020 10-04-2020 10-04-2020 1118
B 08-04-2020 11/04/2020 11/04/2020 6057
B N / D 14-04-2020 14-04-2020 1400
C N / D 01-04-2020 01-04-2020 1156
C N / D 02-04-2020 02-04-2020 6435
C 03-04-2020 03-04-2020 03-04-2020 2847
C 03-04-2020 04-04-2020 04-04-2020 15093
C 03-04-2020 05-04-2020 05-04-2020 2488
C 03-04-2020 06-04-2020 06-04-2020 1773
C N / D 07-04-2020 07-04-2020 8782
C N / D 08-04-2020 08-04-2020 3687
C N / D 11/04/2020 11/04/2020 1963
C N / D 12-04-2020 12-04-2020 9510
C N / D 13/04/2020 13/04/2020 3891
C N / D 14-04-2020 14-04-2020 3282
Leia Também  Animações na época do coronavírus

Já que o padrão em Tabela de dadosde X[i] sintaxe de mesclagem é nomatch = NA, obtemos todos os views de volta, com a coluna promo_date igual à data da última promoção (nos últimos três dias), ou NA se nenhuma promoção for encontrada. Se definirmos nomatch = 0 então, esses valores não correspondentes são eliminados do resultado.

Portanto, a operação completa para calcular os números resumidos é

promos[views, roll = 3, nomatch = 0
       ][j = .(mean = mean(views), sd = sd(views), .N),
         by = video]
UMA 2382 1832 8
B 6131 7836 8
C 5550 6377 4

Se os intervalos precisassem ter durações diferentes para cada uma das campanhas (ou seja, nem todas iguais a 3), você provavelmente desejaria uma junção não equi em vez de uma junção rolante neste caso.

Extensões

Indiscutivelmente, para esses exemplos, você deseja comparar as contagens de visualizações em períodos promocionais com aqueles fora dos períodos promocionais. Isso não requer um tipo especial de junção; em vez disso, você executa a junção não equi ou contínua como acima e, em seguida, organiza a saída de acordo.

Se as linhas não correspondentes forem filtradas, você precisará juntar novamente o conjunto de dados original. Caso contrário, você precisa usar algum tipo de variável indicadora para saber se a data de exibição cai dentro de um período promocional ou não.

No dplyr:

promos %>%
  full_join(views) %>%
  mutate(promo = between(view_date - promo_date, 0, 3)) %>%
  group_by(video, view_date) %>%
  summarise(promo = any(promo),
            views = unique(views)) %>%
  group_by(promo) %>%
  summarise(mean(views), sd(views), n = n())
FALSO 5637 5772 18
VERDADE 4515 5790 20

No Tabela de dados:

promos[views, roll = 3][
         j = .(mean = mean(views), sd = sd(views), .N),
         by = .(promo = !is.na(promo_date))]
VERDADE 4515 5790 20
FALSO 5637 5772 18



[ad_2]

cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br