Cruise Revenue Analysis

Author

Carol Campbell

Published

September 6, 2026

Cruise Revenue Anaylsis

Approach

As an avid cruiser, I searched Kaggle for any dataset that contained data on cruises/cruise ship. I chose one entitled “Cruise Revenue Management Dataset”, a dataset which contains over 77K simulated cruise reservations from 2018 to 2022 designed for Revenue Management, Business Intelligence, Data Analytics and Machine Language projects.

I was particularly drawn to this dataset because I noticed that the column heading were in Spanish. I plan to load the data into R and relabel the column headings, and perform other exploratory data analysis.

Data source:

https://www.kaggle.com/datasets/andresrivasamil/report-cruises-revenue-management

Codebase

Load necessary libraries and the dataset

Code
#Get tidyverse package
library ("tidyverse")
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.2.1     ✔ readr     2.2.0
✔ forcats   1.0.1     ✔ stringr   1.6.0
✔ ggplot2   4.0.3     ✔ tibble    3.3.1
✔ lubridate 1.9.5     ✔ tidyr     1.3.2
✔ purrr     1.2.2     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors

Getting the data from my github repository

Code
#Import the data. My dataset uses commas as delimiters, therefore I specify that in the read function.

cruise_revenue_mgmt_data <- read.csv("https://raw.githubusercontent.com/carolc57/DATA607_Fall2026/b17b3250d9b337491d79d61257788ca21aa06a20/Cruise%20revenue%20report.csv", header = TRUE, sep = ",")

View snippet of dataframe

Code
str(cruise_revenue_mgmt_data)
'data.frame':   77040 obs. of  20 variables:
 $ RES_ID                           : chr  "RES-00001" "RES-00002" "RES-00003" "RES-00004" ...
 $ Fecha_Viaje                      : chr  "1/5/2018" "1/5/2018" "1/5/2018" "1/5/2018" ...
 $ Fecha_Reserva                    : chr  "8/18/2017" "9/14/2017" "11/1/2017" "10/31/2017" ...
 $ Lead_Time_Dias                   : int  140 113 65 66 110 45 55 114 5 57 ...
 $ Noches_Estancia                  : int  6 6 6 6 6 6 6 6 6 6 ...
 $ Barco                            : chr  "MSC World Europa" "MSC World Europa" "MSC World Europa" "MSC World Europa" ...
 $ Compañia                         : chr  "MSC Cruceros" "MSC Cruceros" "MSC Cruceros" "MSC Cruceros" ...
 $ Tipo_Ruta                        : chr  "Mediterráneo" "Mediterráneo" "Mediterráneo" "Mediterráneo" ...
 $ Suite_Type                       : chr  "Balcony" "Interior" "Oceanview" "Interior" ...
 $ Booking_Source                   : chr  "Direct" "B2B" "Web" "Web" ...
 $ Package                          : chr  "All Inclusive" "All Inclusive + EXC" "All Inclusive" "All Inclusive + EXC" ...
 $ Guest_Country                    : chr  "USA" "Spain" "Germany" "USA" ...
 $ Cabinas_Totales_Barco            : int  2626 2626 2626 2626 2626 2626 2626 2626 2626 2626 ...
 $ Cabinas_Reservadas               : int  1 1 1 2 1 1 2 1 1 1 ...
 $ Porcentaje_Ocupacion_Ciclo       : num  87.1 87.1 87.1 87.1 87.1 ...
 $ Pasajeros_Reserva                : int  2 1 2 2 2 2 2 2 2 2 ...
 $ Tripulacion                      : int  2138 2138 2138 2138 2138 2138 2138 2138 2138 2138 ...
 $ Ingreso_Total_Reserva_USD        : num  2762 1863 2760 3884 2723 ...
 $ Gasto_Promedio_Diario_Huesped_USD: num  147 145 147 158 144 ...
 $ Puntuacion_Satisfaccion          : num  4.4 4.3 4.6 4.3 4.3 4.6 4.6 4.4 4.6 4.4 ...

Here we see that there are 77,040 rows of data containing 20 columns but I want to see all the column headings and the type of data they contain, so I use “glimpse” for a listing of all columns.

Code
glimpse (cruise_revenue_mgmt_data)
Rows: 77,040
Columns: 20
$ RES_ID                            <chr> "RES-00001", "RES-00002", "RES-00003…
$ Fecha_Viaje                       <chr> "1/5/2018", "1/5/2018", "1/5/2018", …
$ Fecha_Reserva                     <chr> "8/18/2017", "9/14/2017", "11/1/2017…
$ Lead_Time_Dias                    <int> 140, 113, 65, 66, 110, 45, 55, 114, …
$ Noches_Estancia                   <int> 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, …
$ Barco                             <chr> "MSC World Europa", "MSC World Europ…
$ Compañia                          <chr> "MSC Cruceros", "MSC Cruceros", "MSC…
$ Tipo_Ruta                         <chr> "Mediterráneo", "Mediterráneo", "Med…
$ Suite_Type                        <chr> "Balcony", "Interior", "Oceanview", …
$ Booking_Source                    <chr> "Direct", "B2B", "Web", "Web", "Dire…
$ Package                           <chr> "All Inclusive", "All Inclusive + EX…
$ Guest_Country                     <chr> "USA", "Spain", "Germany", "USA", "U…
$ Cabinas_Totales_Barco             <int> 2626, 2626, 2626, 2626, 2626, 2626, …
$ Cabinas_Reservadas                <int> 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, …
$ Porcentaje_Ocupacion_Ciclo        <dbl> 87.12, 87.12, 87.12, 87.12, 87.12, 8…
$ Pasajeros_Reserva                 <int> 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 4, 2, …
$ Tripulacion                       <int> 2138, 2138, 2138, 2138, 2138, 2138, …
$ Ingreso_Total_Reserva_USD         <dbl> 2762.28, 1863.06, 2760.48, 3883.68, …
$ Gasto_Promedio_Diario_Huesped_USD <dbl> 147.39, 144.91, 147.24, 158.04, 144.…
$ Puntuacion_Satisfaccion           <dbl> 4.4, 4.3, 4.6, 4.3, 4.3, 4.6, 4.6, 4…

Manipulation

Here we see that our data contains 20 columns of various datatypes, including character, interger, double. If we know in advance the attributes of a column it will help us determine the type of analysis that can be performed on that particular column.

We also see that the column heading are in Spanish. Therefore, I will use code to change them to English.

I’m sure that there is a translation package in R that can be used to translate the names of the columns, but that is outside the scope of this exercise. Thus, I will use the rename function (part of the dplyr package) to change the names of the columns.

Code
# Renaming columns using dplyr
cruise_revenue_mgmt_eng <- cruise_revenue_mgmt_data %>%
 rename (Travel_Date = Fecha_Viaje,                    
         Reservation_Date = Fecha_Reserva,                   
         Lead_Time_Days = Lead_Time_Dias,                   
         Nights_Stay = Noches_Estancia,                  
         Ship = Barco,                       
         Company = Compañia,                         
         Route_Type = Tipo_Ruta,                          
         Guest_Home_Country = Guest_Country,                     
         Total_Cabins = Cabinas_Totales_Barco,         
         Num_of_Cabins_Reserved = Cabinas_Reservadas,               
         Cycle_Occupancy_Percentage = Porcentaje_Ocupacion_Ciclo,        
         Passengers_Reservation = Pasajeros_Reserva,                 
         Total_Crew = Tripulacion,                      
         Total_Booking_Revenue_USD = Ingreso_Total_Reserva_USD,       
         Average_Daily_Guest_Spend_USD = Gasto_Promedio_Diario_Huesped_USD,
         Customer_Satisfaction_Score = Puntuacion_Satisfaccion)   

I renamed my original dataframe from “cruise_revenue_mgmt_data” to “cruise_revenue_mgmt_eng” at the same time I renamed the non-english column headings to english.

Code
glimpse (cruise_revenue_mgmt_eng)
Rows: 77,040
Columns: 20
$ RES_ID                        <chr> "RES-00001", "RES-00002", "RES-00003", "…
$ Travel_Date                   <chr> "1/5/2018", "1/5/2018", "1/5/2018", "1/5…
$ Reservation_Date              <chr> "8/18/2017", "9/14/2017", "11/1/2017", "…
$ Lead_Time_Days                <int> 140, 113, 65, 66, 110, 45, 55, 114, 5, 5…
$ Nights_Stay                   <int> 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6…
$ Ship                          <chr> "MSC World Europa", "MSC World Europa", …
$ Company                       <chr> "MSC Cruceros", "MSC Cruceros", "MSC Cru…
$ Route_Type                    <chr> "Mediterráneo", "Mediterráneo", "Mediter…
$ Suite_Type                    <chr> "Balcony", "Interior", "Oceanview", "Int…
$ Booking_Source                <chr> "Direct", "B2B", "Web", "Web", "Direct",…
$ Package                       <chr> "All Inclusive", "All Inclusive + EXC", …
$ Guest_Home_Country            <chr> "USA", "Spain", "Germany", "USA", "USA",…
$ Total_Cabins                  <int> 2626, 2626, 2626, 2626, 2626, 2626, 2626…
$ Num_of_Cabins_Reserved        <int> 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1…
$ Cycle_Occupancy_Percentage    <dbl> 87.12, 87.12, 87.12, 87.12, 87.12, 87.12…
$ Passengers_Reservation        <int> 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 1…
$ Total_Crew                    <int> 2138, 2138, 2138, 2138, 2138, 2138, 2138…
$ Total_Booking_Revenue_USD     <dbl> 2762.28, 1863.06, 2760.48, 3883.68, 2723…
$ Average_Daily_Guest_Spend_USD <dbl> 147.39, 144.91, 147.24, 158.04, 144.14, …
$ Customer_Satisfaction_Score   <dbl> 4.4, 4.3, 4.6, 4.3, 4.3, 4.6, 4.6, 4.4, …

We see that all column headings are now in English.

Rename data within a column

The data in the several columns is non-English. First I’ll get a listing of unique names within those column, then transform them to their English names

First, let’s transform the Ship Column

Code
#Returns a data frame (tibble) with just the unique rows for Ship column
cruise_revenue_mgmt_eng %>% distinct(Ship)
              Ship
1 MSC World Europa
2 Icon of the Seas
3  Norwegian Prima
4     Disney Dream
5   Costa Smeralda
6 Celebrity Beyond
7     Queen Mary 2
8        AIDAcosma

Only “MSC World Europa” and “Costa Smeralda” need to be renamed

Code
# Renaming specific text values in the "Ship" column
cruise_revenue_mgmt_eng <- cruise_revenue_mgmt_eng %>% 
  mutate(Ship = case_match(Ship,
                             "MSC World Europa" ~ "MSC World Europe", 
                             "Costa Smeralda" ~ "Emerald Coast",
                             .default = Ship))#Keeps everything else the same
Warning: There was 1 warning in `mutate()`.
ℹ In argument: `Ship = case_match(...)`.
Caused by warning:
! `case_match()` was deprecated in dplyr 1.2.0.
ℹ Please use `recode_values()` instead.
Code
#Returns a data frame (tibble) with just the unique rows for Ship column
cruise_revenue_mgmt_eng %>% distinct(Ship)
              Ship
1 MSC World Europe
2 Icon of the Seas
3  Norwegian Prima
4     Disney Dream
5    Emerald Coast
6 Celebrity Beyond
7     Queen Mary 2
8        AIDAcosma

Next, I’ll transform everything in the Route_Type column except “Bahamas” and Alaska” which already in English; all others will need to renamed

Code
# Renaming specific text values in the "Route_Type" column
cruise_revenue_mgmt_eng <- cruise_revenue_mgmt_eng %>% 
  mutate(Route_Type = case_match(Route_Type,
                             "Mediterráneo" ~ "Mediterranean", 
                             "Caribe" ~ "Caribbean",
                             "Fiordos" ~ "Fjords", 
                             "Canarias" ~ "Canary Islands",
                             "Transatlántico" ~ "Transatlantic",
                             .default = Route_Type))#Keeps everything else the same


#Returns a data frame (tibble) with just the unique rows for the "Route_Type) column after the mutation
cruise_revenue_mgmt_eng %>% distinct(Route_Type)
      Route_Type
1  Mediterranean
2      Caribbean
3         Fjords
4        Bahamas
5         Alaska
6  Transatlantic
7 Canary Islands

Lastly, the Company column also contains two Spanish names which will need to changed to English as well

Code
cruise_revenue_mgmt_eng <- cruise_revenue_mgmt_eng %>% 
  mutate(Company = case_match(Company,
                              "MSC Cruceros" ~ "MSC Cruises",
                              "Costa Cruceros" ~ "Costa Cruises",
                              .default = Company)) #Keeps everything else the same


#Returns a data frame (tibble) with just the unique rows for the Company column after the mutation
cruise_revenue_mgmt_eng %>% distinct(Company)
                Company
1           MSC Cruises
2       Royal Caribbean
3 Norwegian Cruise Line
4    Disney Cruise Line
5         Costa Cruises
6     Celebrity Cruises
7           Cunard Line
8          AIDA Cruises

##Summary data

Code
summary (cruise_revenue_mgmt_eng)
       RES_ID         Travel_Date     Reservation_Date Lead_Time_Days  
 Length   :77040   Length   :77040   Length   :77040   Min.   :  5.00  
 N.unique :77040   N.unique :  642   N.unique : 1646   1st Qu.: 71.00  
 N.blank  :    0   N.blank  :    0   N.blank  :    0   Median : 98.00  
 Min.nchar:    9   Min.nchar:    8   Min.nchar:    8   Mean   : 99.28  
 Max.nchar:    9   Max.nchar:   10   Max.nchar:   10   3rd Qu.:127.00  
                                                       Max.   :267.00  
  Nights_Stay            Ship            Company          Route_Type   
 Min.   : 3.000   Length   :77040   Length   :77040   Length   :77040  
 1st Qu.: 6.000   N.unique :    8   N.unique :    8   N.unique :    7  
 Median : 7.000   N.blank  :    0   N.blank  :    0   N.blank  :    0  
 Mean   : 7.662   Min.nchar:    9   Min.nchar:   11   Min.nchar:    6  
 3rd Qu.: 9.000   Max.nchar:   16   Max.nchar:   21   Max.nchar:   14  
 Max.   :17.000                                                        
     Suite_Type      Booking_Source       Package      Guest_Home_Country
 Length   :77040   Length   :77040   Length   :77040   Length   :77040   
 N.unique :    4   N.unique :    3   N.unique :    4   N.unique :    8   
 N.blank  :    0   N.blank  :    0   N.blank  :    0   N.blank  :    0   
 Min.nchar:    5   Min.nchar:    3   Min.nchar:   10   Min.nchar:    2   
 Max.nchar:    9   Max.nchar:    6   Max.nchar:   19   Max.nchar:    7   
                                                                         
  Total_Cabins  Num_of_Cabins_Reserved Cycle_Occupancy_Percentage
 Min.   :1250   Min.   :1.000          Min.   : 70.00            
 1st Qu.:1569   1st Qu.:1.000          1st Qu.: 86.82            
 Median :2129   Median :1.000          Median : 91.81            
 Mean   :2083   Mean   :1.151          Mean   : 91.18            
 3rd Qu.:2652   3rd Qu.:1.000          3rd Qu.: 96.38            
 Max.   :2805   Max.   :2.000          Max.   :100.00            
 Passengers_Reservation   Total_Crew   Total_Booking_Revenue_USD
 Min.   :1.000          Min.   :1253   Min.   :  948            
 1st Qu.:1.000          1st Qu.:1409   1st Qu.: 2325            
 Median :2.000          Median :1479   Median : 3210            
 Mean   :1.753          Mean   :1649   Mean   : 3916            
 3rd Qu.:2.000          3rd Qu.:1800   3rd Qu.: 4787            
 Max.   :6.000          Max.   :2350   Max.   :27348            
 Average_Daily_Guest_Spend_USD Customer_Satisfaction_Score
 Min.   : 98.43                Min.   :3.700              
 1st Qu.:142.54                1st Qu.:4.400              
 Median :168.88                Median :4.600              
 Mean   :170.78                Mean   :4.584              
 3rd Qu.:196.55                3rd Qu.:4.800              
 Max.   :271.63                Max.   :5.000              

A cursory view of the summary data tells us that there the data contained therein is from 8 unique cruiselines that offer 4 different types of rooms, have an average sailing time of 7.6 days, average crew of 1649, and average revenue of $3,916 USD.

Thoughts

Many questions come to mind as I conducted my analysis of this dataset, and I like to take a deeper dive using R to answer some if not all of them as my mastery of R improve over the coming weeks. Event though it is manufactured data, I think it’s an excellent dataset to practice the skills learned. One question I’d like to answer is whether not there is a correlation between route traveled by the ship and customer satisfaction. Also, I’d like to know which country has the most bookings for Transatlantic cruises.

AI Use

I did not use AI for this assignment. I did use Google translate to assist with the Spanish to English translation for the data manipulation values.