Without sample data this is kind of a stab in the dark, but I’ll give it a try!
Creating some dummy data according to your description.
library(dplyr, warn.conflicts = FALSE)
owner_df <-
  purrr::map_dfr(1:5, ~ {
    owner1_names <-
      do.call(paste0, replicate(5, sample(LETTERS, 3, TRUE), FALSE))
    owner2_names <-
      do.call(paste0, replicate(5, sample(LETTERS, 1, TRUE), FALSE))
    tibble(
      property = .,
      year = 2000:2019,
      owner1 = sort(sample(owner1_names, 20, replace = TRUE)),
      owner2 = sample(
        c("-empty-", owner2_names), 20, replace = TRUE
      )
    )
  })
As akrun commented dplyr::lag() is helpful here, to detect when there
is change in the
owner2 variable. Whenever owner2 and owner2_lag are not the same, a change happened.
In order to only detect changes when owner 1 stays the same
and owner 2 changes, we include owner 1 in the grouping and create
a logical variable for each kind of change that can happen (marriage,
divorce, and a third situation where a parter is swapped for another one).
owner_df %>%
  group_by(property, owner1) %>%
  mutate(
    owner2_lagged = lag(owner2, default = first(owner2)),
    change_detected = owner2 != owner2_lagged,
    marriage = change_detected & owner2_lagged == "-empty-",
    divorce = change_detected & owner2 == "-empty-",
    partner_swap = change_detected &
      owner2_lagged != "-empty-" & owner2 != "-empty-"
  )
#> # A tibble: 100 x 9
#> # Groups:   property, owner1 [15]
#>    property  year owner1 owner2 owner2_lagged change_detected marriage divorce
#>       <int> <int> <chr>  <chr>  <chr>         <lgl>           <lgl>    <lgl>  
#>  1        1  2000 OKWBQ  QSSVZ  QSSVZ         FALSE           FALSE    FALSE  
#>  2        1  2001 OKWBQ  -empt… QSSVZ         TRUE            FALSE    TRUE   
#>  3        1  2002 OKWBQ  -empt… -empty-       FALSE           FALSE    FALSE  
#>  4        1  2003 OKWBQ  QSSVZ  -empty-       TRUE            TRUE     FALSE  
#>  5        1  2004 OKWBQ  -empt… QSSVZ         TRUE            FALSE    TRUE   
#>  6        1  2005 OKWBQ  -empt… -empty-       FALSE           FALSE    FALSE  
#>  7        1  2006 OKWBQ  -empt… -empty-       FALSE           FALSE    FALSE  
#>  8        1  2007 OYQEJ  QSSVZ  QSSVZ         FALSE           FALSE    FALSE  
#>  9        1  2008 OYQEJ  QSSVZ  QSSVZ         FALSE           FALSE    FALSE  
#> 10        1  2009 OYQEJ  QSSVZ  QSSVZ         FALSE           FALSE    FALSE  
#> # … with 90 more rows, and 1 more variable: partner_swap <lgl>
Alternatively you can use dplyr::case_when() to create one variable marking
the type of change.
owner_df %>%
  group_by(property, owner1) %>%
  mutate(
    owner2_lagged = lag(owner2, default = first(owner2)),
    change_detected = owner2 != owner2_lagged,
    type_of_change = case_when(
      change_detected & owner2_lagged == "-empty-" ~ "marriage",
      change_detected & owner2 == "-empty-" ~ "divorce",
      change_detected &
        owner2_lagged != "-empty-" & owner2 != "-empty-" ~ "partner_swap"
    )
  )
#> # A tibble: 100 x 7
#> # Groups:   property, owner1 [15]
#>    property  year owner1 owner2  owner2_lagged change_detected type_of_change
#>       <int> <int> <chr>  <chr>   <chr>         <lgl>           <chr>         
#>  1        1  2000 OKWBQ  QSSVZ   QSSVZ         FALSE           <NA>          
#>  2        1  2001 OKWBQ  -empty- QSSVZ         TRUE            divorce       
#>  3        1  2002 OKWBQ  -empty- -empty-       FALSE           <NA>          
#>  4        1  2003 OKWBQ  QSSVZ   -empty-       TRUE            marriage      
#>  5        1  2004 OKWBQ  -empty- QSSVZ         TRUE            divorce       
#>  6        1  2005 OKWBQ  -empty- -empty-       FALSE           <NA>          
#>  7        1  2006 OKWBQ  -empty- -empty-       FALSE           <NA>          
#>  8        1  2007 OYQEJ  QSSVZ   QSSVZ         FALSE           <NA>          
#>  9        1  2008 OYQEJ  QSSVZ   QSSVZ         FALSE           <NA>          
#> 10        1  2009 OYQEJ  QSSVZ   QSSVZ         FALSE           <NA>          
#> # … with 90 more rows