Findings - Dinâmica da Conversa

Volume, ritmo e padrões temporais ao longo de um ano

Author

Marlon

Published

May 7, 2026

Resumo

Ao longo dos 308 dias em que P1 e P2 namoraram (16/dez/2024 a 20/out/2025), foram trocadas 89.336 mensagens — uma média de 297 mensagens por dia, com picos que passam de 1.200. Esta análise consolida o quando da conversa: volume total, evolução mensal, padrões de dia da semana e hora do dia, e o efeito de estarem juntos ou separados.

A curva do ano não é linear — ela tem um pico pronunciado no inverno (jun–jul/2025) e uma queda brusca nas últimas semanas.


Setup

Code
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from pathlib import Path
import warnings
warnings.filterwarnings('ignore')

from whatsapp.pipeline.config import DATA_FOLDER
DATA_DIR = Path("../data/processed") / DATA_FOLDER

df = pd.read_parquet(DATA_DIR / 'messages_enriched.parquet')
dfc = pd.read_parquet(DATA_DIR / 'messages_with_context.parquet')
df['fase_relacionamento'] = dfc['fase_relacionamento']

# Foco na fase Relacionamento (pós 16/dez/2024)
df = df[df['fase_relacionamento'] == 'Relacionamento'].copy()
df['timestamp'] = pd.to_datetime(df['timestamp'])
df['data'] = pd.to_datetime(df['data'])

print(f"Mensagens: {len(df):,}")
print(f"Período: {df['timestamp'].min().date()} → {df['timestamp'].max().date()}")
print(f"Duração: {(df['timestamp'].max() - df['timestamp'].min()).days} dias")
Mensagens: 89,336
Período: 2024-12-16 → 2025-10-20
Duração: 308 dias

Escala

Números-chave

  • 89.336 mensagens
  • 308 dias de relacionamento
  • 297 msgs/dia (média)
  • 228 msgs/dia (mediana)
  • 1.288 msgs no dia de pico (22/jun/2025)

Encontros

  • 110/301 dias juntos (36,5%)
  • 191/301 dias separados (63,5%)
  • 121 msgs/dia em encontro
  • 398 msgs/dia separados (~3× mais)

O fato mais contraintuitivo: separados mandam 3× mais mensagens por dia do que juntos. Isso não significa que juntos se falam menos — significa que parte do que seria conversa escrita vira conversa presencial.


Evolução mensal — o arco do ano

Code
mensal = df.groupby(df['timestamp'].dt.to_period('M')).size().reset_index(name='msgs')
mensal['periodo'] = mensal['timestamp'].astype(str)
mensal['dias_no_mes'] = df.groupby(df['timestamp'].dt.to_period('M'))['data'].nunique().values
mensal['media_diaria'] = (mensal['msgs'] / mensal['dias_no_mes']).round(0)

fig = make_subplots(specs=[[{"secondary_y": True}]])
fig.add_trace(
    go.Bar(x=mensal['periodo'], y=mensal['msgs'], name='Total do mês',
           marker_color='#4C78A8', opacity=0.8,
           text=mensal['msgs'].apply(lambda x: f'{x:,}'), textposition='outside')
)
fig.add_trace(
    go.Scatter(x=mensal['periodo'], y=mensal['media_diaria'],
               name='Média diária', mode='lines+markers',
               line=dict(color='#F58518', width=3),
               marker=dict(size=10)),
    secondary_y=True
)

fig.update_layout(
    height=450,
    title_text="Volume mensal — total e média diária",
    xaxis_title="Mês",
    hovermode='x unified'
)
fig.update_yaxes(title_text="Total de mensagens", secondary_y=False)
fig.update_yaxes(title_text="Média diária", secondary_y=True)
fig.show()

Leitura:

  • O relacionamento começa forte (janeiro/2025 = 9.240 msgs), esfria em abril (queda pra 4.041), e então explode em jun–jul (14k e 17.4k). É o ápice de volume do ano.
  • Agosto ainda é intenso (12.8k), mas a partir de setembro cai bruscamente (3.2k) e outubro encerra em 3.1k — queda de ~75% frente ao pico.
  • Essa queda final pode refletir estarem mais juntos fisicamente, menor necessidade de texto, ou mudança na dinâmica (ver notebook de sentimento para cross-check).

Padrões diários — hora do dia e dia da semana

Code
# Garantir ordem PT-BR
ordem_dias = ['Segunda', 'Terça', 'Quarta', 'Quinta', 'Sexta', 'Sábado', 'Domingo']
df['dia_semana_ord'] = pd.Categorical(df['dia_semana'], categories=ordem_dias, ordered=True)

heat = df.groupby(['dia_semana_ord', 'hora'], observed=True).size().reset_index(name='msgs')
pivot = heat.pivot(index='dia_semana_ord', columns='hora', values='msgs').fillna(0)
pivot = pivot.reindex(ordem_dias)

fig = go.Figure(data=go.Heatmap(
    z=pivot.values,
    x=pivot.columns,
    y=pivot.index,
    colorscale='Blues',
    colorbar=dict(title="Msgs"),
    hovertemplate='%{y} %{x}h: %{z:,} msgs<extra></extra>'
))
fig.update_layout(
    height=400,
    title_text="Heatmap: dia da semana × hora do dia",
    xaxis_title="Hora do dia",
    yaxis_title="",
    xaxis=dict(tickmode='linear', tick0=0, dtick=2)
)
fig.show()

Leitura do heatmap:

  • Zonas mortas (0–7h): conversa dorme. Exceção leve na madrugada de sex→sáb (tem alguma atividade nas primeiras horas).
  • Crescimento suave ao longo do dia: volume aumenta a partir das 9h, se estabiliza alto entre 10h–22h.
  • Pico forte entre 17h–20h, com máximo às 19h. Conversa “depois do trabalho” é o momento mais intenso.
  • Finais de semana são mais intensos que dias úteis em horário noturno — especialmente domingo à noite.

Distribuição por hora (visão agregada)

Code
hora = df.groupby('hora').size().reset_index(name='msgs')

fig = go.Figure()
fig.add_trace(go.Bar(
    x=hora['hora'], y=hora['msgs'],
    marker_color='#4C78A8',
    text=hora['msgs'], textposition='outside'
))
fig.update_layout(
    height=380,
    title_text="Mensagens por hora do dia (total do período)",
    xaxis_title="Hora",
    yaxis_title="Mensagens",
    xaxis=dict(tickmode='linear', tick0=0, dtick=1)
)
fig.show()

O ritmo é o de um casal com vida ativa: conversa acorda junto com a manhã, ganha força entre 11h e 13h (almoço), sobe de novo entre 15h e 20h (final da tarde/início da noite), e decai gradualmente.


Juntos vs. separados — quanto pesa a distância?

Code
comp = df.groupby('em_encontro').agg(
    total_msgs=('timestamp', 'count'),
    dias_distintos=('data', 'nunique')
).reset_index()
comp['rotulo'] = comp['em_encontro'].map({True: 'Juntos', False: 'Separados'})
comp['msgs_por_dia'] = (comp['total_msgs'] / comp['dias_distintos']).round(0)

fig = make_subplots(
    rows=1, cols=2,
    subplot_titles=('Total de mensagens', 'Média por dia'),
)
fig.add_trace(
    go.Bar(x=comp['rotulo'], y=comp['total_msgs'],
           marker_color=['#2ECC71', '#E74C3C'],
           text=comp['total_msgs'].apply(lambda x: f'{x:,}'),
           textposition='outside', showlegend=False),
    row=1, col=1
)
fig.add_trace(
    go.Bar(x=comp['rotulo'], y=comp['msgs_por_dia'],
           marker_color=['#2ECC71', '#E74C3C'],
           text=comp['msgs_por_dia'].apply(lambda x: f'{int(x):,}'),
           textposition='outside', showlegend=False),
    row=1, col=2
)
fig.update_layout(height=400, title_text="Volume: juntos vs. separados")
fig.show()

Leitura:

  • Apesar de estarem juntos em 36,5% dos dias, apenas 15% das mensagens aconteceram nesses dias. A conversa escrita é majoritariamente um substituto para presença.
  • Mesmo juntos, mandam 121 mensagens/dia em média — ou seja, conversa por texto não desaparece totalmente quando estão no mesmo lugar (vídeos, memes, tarefas logísticas, links).

Picos e vales

Code
diario = df.groupby('data').size().reset_index(name='msgs')
diario = diario.sort_values('msgs', ascending=False)

# Top 5 e bottom 5 (só dias com >=1 msg)
top = diario.head(5).copy()
bot = diario.tail(5).copy()
top['tipo'] = 'Top 5'
bot['tipo'] = 'Menores 5'
picos_df = pd.concat([top, bot])
picos_df['data_str'] = picos_df['data'].dt.strftime('%Y-%m-%d')

print("Top 5 dias de maior volume:")
print(top[['data', 'msgs']].to_string(index=False))
print("\nMenores 5 dias:")
print(bot[['data', 'msgs']].to_string(index=False))
Top 5 dias de maior volume:
      data  msgs
2025-06-22  1288
2025-07-06  1198
2025-07-05  1156
2025-08-17  1116
2025-07-16  1078

Menores 5 dias:
      data  msgs
2025-03-08     1
2025-10-04     1
2025-05-23     1
2025-09-27     1
2025-05-18     1

O pico absoluto é 22/jun/2025 com 1.288 mensagens — um domingo. Olhar o que aconteceu nesses picos/vales específicos pode render microhistórias (ver notebook de temas e sentimento).


Conclusões

  1. O relacionamento gerou ~89 mil mensagens em ~10 meses — equivalente a ~297 msgs/dia de média, com mediana em 228. A conversa é de alta frequência.

  2. O arco do ano tem forma clara: começa forte (dez–jan), dá uma respirada em abril, explode no inverno (jun–jul foi o ápice com 17k msgs em julho), e cai drasticamente nas últimas semanas (setembro e outubro com ~3k cada).

  3. Distância alimenta o texto. Quando separados, mandam ~3× mais mensagens por dia do que quando juntos — a conversa escrita é, fundamentalmente, um preenchimento da ausência.

  4. A conversa tem um ritmo diário estável. Picos entre 17h–20h, menor atividade de madrugada. Finais de semana à noite são os momentos mais carregados.

  5. Juntos ≠ silêncio. Mesmo presencialmente, mandam ~121 msgs/dia — vídeos, tarefas, logística. Texto coexiste com presença.

TipVer também