Στην παρούσα εργασία χρησιμοποιείται το Kickstarter Projects dataset, το οποίο περιέχει δεδομένα από καμπάνιες crowdfunding που δημοσιεύτηκαν στην πλατφόρμα Kickstarter έως τον Ιανουάριο του 2018.
Το ερευνητικό ερώτημα είναι: «Μπορούμε να προβλέψουμε αν μια καμπάνια Kickstarter θα πετύχει τον χρηματοδοτικό της στόχο;»
Πηγή: Kaggle
– Kickstarter Projects
Αρχείο: ks-projects-201801.csv
Οδηγίες φόρτωσης: Κατεβάστε το αρχείο
ks-projects-201801.csvαπό το Kaggle και τοποθετήστε το στον ίδιο φάκελο με το παρόν.Rmdαρχείο.
| Μεταβλητή | Τύπος | Περιγραφή |
|---|---|---|
| state | Binary (0/1) | Αποτέλεσμα καμπάνιας — εξαρτημένη μεταβλητή |
| main_category | Κατηγορική | Κύρια κατηγορία project (Film, Music, Games κ.λπ.) |
| usd_goal_real | Αριθμητική | Στόχος χρηματοδότησης σε USD |
| country | Κατηγορική | Χώρα προέλευσης του δημιουργού |
| duration_days | Αριθμητική | Διάρκεια καμπάνιας σε ημέρες (υπολογιζόμενη) |
| launch_month | Κατηγορική | Μήνας έναρξης καμπάνιας (εποχικότητα) |
| launch_year | Κατηγορική | Έτος έναρξης καμπάνιας |
Σημείωση για την εξαρτημένη μεταβλητή: Το αρχικό πεδίο
stateπεριέχει πολλές κατηγορίες (successful, failed, canceled, live, suspended). Διατηρούμε μόνο τιςsuccessful(= 1) καιfailed(= 0), αφαιρώντας τις υπόλοιπες.
pkgs <- c("caTools", "ROCR", "dplyr", "ggplot2", "scales", "knitr", "lubridate")
for (p in pkgs) {
if (!require(p, character.only = TRUE, quietly = TRUE)) {
# Προσθέτουμε το repos="[https://cloud.r-project.org](https://cloud.r-project.org)"
install.packages(p, repos = "[https://cloud.r-project.org](https://cloud.r-project.org)", quiet = TRUE)
library(p, character.only = TRUE)
}
}# Διαβάστε το CSV από τον τρέχοντα φάκελο
# Αν το αρχείο βρίσκεται σε άλλο μονοπάτι, αλλάξτε το path εδώ:
df_raw <- read.csv("/Users/omirosloupis/Desktop/BUSINESS ANALYTICS/ergasies/ks-projects-201801.csv",
stringsAsFactors = FALSE,
encoding = "UTF-8")
cat("Αρχικές διαστάσεις dataset:", nrow(df_raw), "x", ncol(df_raw), "\n")## Αρχικές διαστάσεις dataset: 378661 x 15
## Μεταβλητές: ID, name, category, main_category, currency, deadline, goal, launched, pledged, state, backers, country, usd.pledged, usd_pledged_real, usd_goal_real
# Κατανομή όλων των κατηγοριών state πριν τον φιλτραρισμό
state_counts <- as.data.frame(table(df_raw$state))
names(state_counts) <- c("State", "Count")
state_counts$Pct <- round(state_counts$Count / sum(state_counts$Count) * 100, 1)
kable(state_counts,
caption = "Κατανομή Κατηγοριών State (αρχικό dataset)",
row.names = FALSE,
align = "lrr")| State | Count | Pct |
|---|---|---|
| canceled | 38779 | 10.2 |
| failed | 197719 | 52.2 |
| live | 2799 | 0.7 |
| successful | 133956 | 35.4 |
| suspended | 1846 | 0.5 |
| undefined | 3562 | 0.9 |
# Top κατηγορίες
top_cats <- df_raw %>%
filter(state %in% c("successful", "failed")) %>%
count(main_category, state) %>%
group_by(main_category) %>%
mutate(total = sum(n)) %>%
ungroup() %>%
mutate(main_category = reorder(main_category, total))
ggplot(top_cats, aes(x = main_category, y = n, fill = state)) +
geom_bar(stat = "identity", position = "stack", alpha = 0.85) +
scale_fill_manual(values = c("failed" = "#e74c3c", "successful" = "#2ecc71"),
labels = c("Αποτυχία", "Επιτυχία")) +
coord_flip() +
labs(title = "Αριθμός Καμπανιών ανά Κατηγορία & Αποτέλεσμα",
x = "Κατηγορία",
y = "Αριθμός Καμπανιών",
fill = "Αποτέλεσμα") +
theme_minimal(base_size = 12) +
theme(plot.title = element_text(face = "bold"))# Ποσοστό επιτυχίας ανά κατηγορία
success_rate <- df_raw %>%
filter(state %in% c("successful", "failed")) %>%
group_by(main_category) %>%
summarise(
Total = n(),
Successful = sum(state == "successful"),
Rate_pct = round(Successful / Total * 100, 1)
) %>%
arrange(desc(Rate_pct))
kable(success_rate,
caption = "Ποσοστό Επιτυχίας ανά Κύρια Κατηγορία",
row.names = FALSE,
align = "lrrr")| main_category | Total | Successful | Rate_pct |
|---|---|---|---|
| Dance | 3573 | 2338 | 65.4 |
| Theater | 10242 | 6534 | 63.8 |
| Comics | 9878 | 5842 | 59.1 |
| Music | 45949 | 24197 | 52.7 |
| Art | 25641 | 11510 | 44.9 |
| Games | 28521 | 12518 | 43.9 |
| Film & Video | 56527 | 23623 | 41.8 |
| Design | 25364 | 10550 | 41.6 |
| Publishing | 35445 | 12300 | 34.7 |
| Photography | 9689 | 3305 | 34.1 |
| Fashion | 19775 | 5593 | 28.3 |
| Food | 22054 | 6085 | 27.6 |
| Crafts | 7818 | 2115 | 27.1 |
| Journalism | 4149 | 1012 | 24.4 |
| Technology | 27050 | 6434 | 23.8 |
df_model <- df_raw %>%
# 1. Κρατάμε μόνο successful & failed
filter(state %in% c("successful", "failed")) %>%
# 2. Μετατροπή ημερομηνιών
mutate(
launched = ymd_hms(launched),
deadline = ymd(deadline)
) %>%
# 3. Υπολογισμός διάρκειας καμπάνιας (ημέρες)
mutate(
duration_days = as.integer(difftime(deadline, launched, units = "days")),
launch_month = as.factor(month(launched)),
launch_year = as.factor(year(launched))
) %>%
# 4. Δυαδική εξαρτημένη μεταβλητή — integer για συμβατότητα με ROCR
mutate(
state_binary = as.integer(state == "successful")
) %>%
# 5. Επιλογή τελικών μεταβλητών
select(state_binary, main_category, usd_goal_real,
country, duration_days, launch_month, launch_year) %>%
# 6. Κατηγορικές μεταβλητές ως factor
mutate(
main_category = as.factor(main_category),
country = as.factor(country)
) %>%
# 7. Αφαίρεση εξωφρενικών τιμών στόχου (< $1 ή > $10M)
filter(usd_goal_real >= 1, usd_goal_real <= 10000000) %>%
# 8. Αφαίρεση αδύνατης διάρκειας
filter(duration_days > 0, duration_days <= 92)
cat("Διαστάσεις μετά επεξεργασία:", nrow(df_model), "x", ncol(df_model), "\n")## Διαστάσεις μετά επεξεργασία: 331446 x 7
## Κατανομή εξαρτημένης (0=Failed, 1=Successful):
##
## 0 1
## 197548 133898
## Ποσοστό επιτυχίας: 40.4 %
## Σύνολο NA : 0
# Κατανομή στόχου χρηματοδότησης (log scale)
ggplot(df_model, aes(x = usd_goal_real, fill = factor(state_binary))) +
geom_histogram(bins = 60, alpha = 0.7, position = "identity") +
scale_x_log10(labels = scales::dollar_format()) +
scale_fill_manual(values = c("0" = "#e74c3c", "1" = "#2ecc71"),
labels = c("Αποτυχία", "Επιτυχία")) +
labs(title = "Κατανομή Στόχου Χρηματοδότησης (log scale)",
x = "Στόχος USD (log)",
y = "Πλήθος Καμπανιών",
fill = "Αποτέλεσμα") +
theme_minimal(base_size = 12) +
theme(plot.title = element_text(face = "bold"))# Διάρκεια καμπάνιας ανά αποτέλεσμα
ggplot(df_model, aes(x = factor(state_binary), y = duration_days,
fill = factor(state_binary))) +
geom_boxplot(alpha = 0.8, outlier.alpha = 0.2) +
scale_fill_manual(values = c("0" = "#e74c3c", "1" = "#2ecc71")) +
scale_x_discrete(labels = c("0" = "Αποτυχία", "1" = "Επιτυχία")) +
labs(title = "Διάρκεια Καμπάνιας ανά Αποτέλεσμα",
x = "Αποτέλεσμα",
y = "Διάρκεια (ημέρες)") +
theme_minimal(base_size = 12) +
theme(legend.position = "none",
plot.title = element_text(face = "bold"))Seed: Ορίζεται ως 942 — τα 2 τελευταία ψηφία (42) αντιστοιχούν στα 2 τελευταία ψηφία του ιδρυματικού email. Το training set αποτελεί το 65% της βάσης.
set.seed(942)
split_idx <- sample.split(df_model$state_binary, SplitRatio = 0.65)
train <- subset(df_model, split_idx == TRUE)
test <- subset(df_model, split_idx == FALSE)
cat("╔═══════════════════════════════════════════╗\n")## ╔═══════════════════════════════════════════╗
## ║ ΑΡΙΘΜΟΣ ΚΑΤΑΧΩΡΗΣΕΩΝ ║
## ╠═══════════════════════════════════════════╣
## ║ Training set (train) : 215440 καταχωρήσεις ║
## ║ Testing set (test) : 116006 καταχωρήσεις ║
## ║ Συνολο : 331446 καταχωρήσεις ║
## ║ Ποσοστο train : 65.0% ║
## ╚═══════════════════════════════════════════╝
##
## Call:
## glm(formula = state_binary ~ ., family = binomial(link = "logit"),
## data = train)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 4.949e-01 1.642e-01 3.014 0.002577 **
## main_categoryComics 5.935e-01 3.039e-02 19.528 < 2e-16 ***
## main_categoryCrafts -7.491e-01 3.588e-02 -20.874 < 2e-16 ***
## main_categoryDance 8.648e-01 4.728e-02 18.290 < 2e-16 ***
## main_categoryDesign 1.143e-01 2.309e-02 4.953 7.31e-07 ***
## main_categoryFashion -6.391e-01 2.560e-02 -24.960 < 2e-16 ***
## main_categoryFilm & Video -2.177e-02 1.948e-02 -1.117 0.263813
## main_categoryFood -5.257e-01 2.510e-02 -20.949 < 2e-16 ***
## main_categoryGames 1.227e-01 2.226e-02 5.511 3.56e-08 ***
## main_categoryJournalism -7.540e-01 4.826e-02 -15.625 < 2e-16 ***
## main_categoryMusic 3.144e-01 1.993e-02 15.773 < 2e-16 ***
## main_categoryPhotography -4.326e-01 3.157e-02 -13.701 < 2e-16 ***
## main_categoryPublishing -3.976e-01 2.128e-02 -18.682 < 2e-16 ***
## main_categoryTechnology -5.079e-01 2.477e-02 -20.509 < 2e-16 ***
## main_categoryTheater 7.615e-01 3.071e-02 24.797 < 2e-16 ***
## usd_goal_real -1.384e-05 2.570e-07 -53.857 < 2e-16 ***
## countryAU 4.661e-01 1.459e-01 3.195 0.001398 **
## countryBE 2.874e-01 1.923e-01 1.495 0.134971
## countryCA 4.899e-01 1.439e-01 3.404 0.000665 ***
## countryCH 4.528e-01 1.810e-01 2.502 0.012351 *
## countryDE 2.865e-01 1.503e-01 1.907 0.056534 .
## countryDK 7.123e-01 1.679e-01 4.243 2.21e-05 ***
## countryES 1.588e-01 1.574e-01 1.009 0.312964
## countryFR 7.241e-01 1.516e-01 4.776 1.79e-06 ***
## countryGB 7.359e-01 1.426e-01 5.159 2.48e-07 ***
## countryHK 1.059e+00 1.827e-01 5.799 6.68e-09 ***
## countryIE 3.438e-01 1.787e-01 1.924 0.054346 .
## countryIT -1.738e-01 1.572e-01 -1.106 0.268938
## countryJP 8.357e-01 5.484e-01 1.524 0.127540
## countryLU 7.136e-01 3.719e-01 1.919 0.055025 .
## countryMX -8.167e-02 1.611e-01 -0.507 0.612213
## countryN,0" 6.984e-01 2.262e-01 3.087 0.002020 **
## countryNL 3.472e-01 1.538e-01 2.257 0.023994 *
## countryNO 3.031e-01 1.834e-01 1.652 0.098438 .
## countryNZ 5.767e-01 1.603e-01 3.597 0.000322 ***
## countrySE 5.821e-01 1.582e-01 3.679 0.000234 ***
## countrySG 6.643e-01 1.916e-01 3.467 0.000526 ***
## countryUS 7.329e-01 1.420e-01 5.162 2.44e-07 ***
## duration_days -2.032e-02 3.990e-04 -50.914 < 2e-16 ***
## launch_month2 1.505e-01 2.360e-02 6.376 1.82e-10 ***
## launch_month3 1.679e-01 2.287e-02 7.341 2.12e-13 ***
## launch_month4 1.256e-01 2.322e-02 5.412 6.24e-08 ***
## launch_month5 7.771e-02 2.309e-02 3.366 0.000762 ***
## launch_month6 4.962e-02 2.314e-02 2.144 0.032029 *
## launch_month7 -9.879e-02 2.292e-02 -4.310 1.63e-05 ***
## launch_month8 -3.634e-02 2.341e-02 -1.552 0.120643
## launch_month9 8.926e-02 2.355e-02 3.791 0.000150 ***
## launch_month10 1.616e-01 2.305e-02 7.010 2.38e-12 ***
## launch_month11 1.138e-01 2.328e-02 4.889 1.01e-06 ***
## launch_month12 -6.998e-02 2.642e-02 -2.649 0.008081 **
## launch_year2010 -4.048e-01 7.986e-02 -5.069 4.00e-07 ***
## launch_year2011 -4.035e-01 7.745e-02 -5.209 1.90e-07 ***
## launch_year2012 -6.174e-01 7.718e-02 -7.999 1.25e-15 ***
## launch_year2013 -5.218e-01 7.723e-02 -6.756 1.41e-11 ***
## launch_year2014 -8.981e-01 7.702e-02 -11.660 < 2e-16 ***
## launch_year2015 -9.981e-01 7.706e-02 -12.951 < 2e-16 ***
## launch_year2016 -7.360e-01 7.729e-02 -9.523 < 2e-16 ***
## launch_year2017 -5.931e-01 7.751e-02 -7.652 1.99e-14 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 290669 on 215439 degrees of freedom
## Residual deviance: 268013 on 215382 degrees of freedom
## AIC: 268129
##
## Number of Fisher Scoring iterations: 7
coef_table <- summary(model)$coefficients
coef_df <- data.frame(
Metavliti = rownames(coef_table),
Ektimisi = round(coef_table[, "Estimate"], 4),
Std_Error = round(coef_table[, "Std. Error"], 4),
z_value = round(coef_table[, "z value"], 4),
p_value = round(coef_table[, "Pr(>|z|)"], 6),
Simantikotita = ifelse(coef_table[, "Pr(>|z|)"] < 0.001, "*** p < 0.001",
ifelse(coef_table[, "Pr(>|z|)"] < 0.01, "** p < 0.01",
ifelse(coef_table[, "Pr(>|z|)"] < 0.05, "* p < 0.05",
ifelse(coef_table[, "Pr(>|z|)"] < 0.1, ". p < 0.1",
"— Μη σημαντικό"))))
)
kable(coef_df,
caption = "Συντελεστές Λογιστικής Παλινδρόμησης",
row.names = FALSE,
align = "lrrrrl")| Metavliti | Ektimisi | Std_Error | z_value | p_value | Simantikotita |
|---|---|---|---|---|---|
| (Intercept) | 0.4949 | 0.1642 | 3.0142 | 0.002577 | ** p < 0.01 |
| main_categoryComics | 0.5935 | 0.0304 | 19.5282 | 0.000000 | *** p < 0.001 |
| main_categoryCrafts | -0.7491 | 0.0359 | -20.8744 | 0.000000 | *** p < 0.001 |
| main_categoryDance | 0.8648 | 0.0473 | 18.2902 | 0.000000 | *** p < 0.001 |
| main_categoryDesign | 0.1143 | 0.0231 | 4.9529 | 0.000001 | *** p < 0.001 |
| main_categoryFashion | -0.6391 | 0.0256 | -24.9601 | 0.000000 | *** p < 0.001 |
| main_categoryFilm & Video | -0.0218 | 0.0195 | -1.1174 | 0.263813 | — Μη σημαντικό |
| main_categoryFood | -0.5257 | 0.0251 | -20.9486 | 0.000000 | *** p < 0.001 |
| main_categoryGames | 0.1227 | 0.0223 | 5.5113 | 0.000000 | *** p < 0.001 |
| main_categoryJournalism | -0.7540 | 0.0483 | -15.6253 | 0.000000 | *** p < 0.001 |
| main_categoryMusic | 0.3144 | 0.0199 | 15.7733 | 0.000000 | *** p < 0.001 |
| main_categoryPhotography | -0.4326 | 0.0316 | -13.7007 | 0.000000 | *** p < 0.001 |
| main_categoryPublishing | -0.3976 | 0.0213 | -18.6822 | 0.000000 | *** p < 0.001 |
| main_categoryTechnology | -0.5079 | 0.0248 | -20.5089 | 0.000000 | *** p < 0.001 |
| main_categoryTheater | 0.7615 | 0.0307 | 24.7967 | 0.000000 | *** p < 0.001 |
| usd_goal_real | 0.0000 | 0.0000 | -53.8567 | 0.000000 | *** p < 0.001 |
| countryAU | 0.4661 | 0.1459 | 3.1952 | 0.001398 | ** p < 0.01 |
| countryBE | 0.2874 | 0.1923 | 1.4948 | 0.134971 | — Μη σημαντικό |
| countryCA | 0.4899 | 0.1439 | 3.4036 | 0.000665 | *** p < 0.001 |
| countryCH | 0.4528 | 0.1810 | 2.5019 | 0.012351 | * p < 0.05 |
| countryDE | 0.2865 | 0.1503 | 1.9069 | 0.056534 | . p < 0.1 |
| countryDK | 0.7123 | 0.1679 | 4.2427 | 0.000022 | *** p < 0.001 |
| countryES | 0.1588 | 0.1574 | 1.0090 | 0.312964 | — Μη σημαντικό |
| countryFR | 0.7241 | 0.1516 | 4.7757 | 0.000002 | *** p < 0.001 |
| countryGB | 0.7359 | 0.1426 | 5.1591 | 0.000000 | *** p < 0.001 |
| countryHK | 1.0592 | 0.1827 | 5.7987 | 0.000000 | *** p < 0.001 |
| countryIE | 0.3438 | 0.1787 | 1.9241 | 0.054346 | . p < 0.1 |
| countryIT | -0.1738 | 0.1572 | -1.1055 | 0.268938 | — Μη σημαντικό |
| countryJP | 0.8357 | 0.5484 | 1.5239 | 0.127540 | — Μη σημαντικό |
| countryLU | 0.7136 | 0.3719 | 1.9187 | 0.055025 | . p < 0.1 |
| countryMX | -0.0817 | 0.1611 | -0.5069 | 0.612213 | — Μη σημαντικό |
| countryN,0” | 0.6984 | 0.2262 | 3.0873 | 0.002020 | ** p < 0.01 |
| countryNL | 0.3472 | 0.1538 | 2.2572 | 0.023994 | * p < 0.05 |
| countryNO | 0.3031 | 0.1834 | 1.6525 | 0.098438 | . p < 0.1 |
| countryNZ | 0.5767 | 0.1603 | 3.5970 | 0.000322 | *** p < 0.001 |
| countrySE | 0.5821 | 0.1582 | 3.6795 | 0.000234 | *** p < 0.001 |
| countrySG | 0.6643 | 0.1916 | 3.4670 | 0.000526 | *** p < 0.001 |
| countryUS | 0.7329 | 0.1420 | 5.1624 | 0.000000 | *** p < 0.001 |
| duration_days | -0.0203 | 0.0004 | -50.9136 | 0.000000 | *** p < 0.001 |
| launch_month2 | 0.1505 | 0.0236 | 6.3761 | 0.000000 | *** p < 0.001 |
| launch_month3 | 0.1679 | 0.0229 | 7.3411 | 0.000000 | *** p < 0.001 |
| launch_month4 | 0.1256 | 0.0232 | 5.4118 | 0.000000 | *** p < 0.001 |
| launch_month5 | 0.0777 | 0.0231 | 3.3661 | 0.000762 | *** p < 0.001 |
| launch_month6 | 0.0496 | 0.0231 | 2.1440 | 0.032029 | * p < 0.05 |
| launch_month7 | -0.0988 | 0.0229 | -4.3104 | 0.000016 | *** p < 0.001 |
| launch_month8 | -0.0363 | 0.0234 | -1.5521 | 0.120643 | — Μη σημαντικό |
| launch_month9 | 0.0893 | 0.0235 | 3.7910 | 0.000150 | *** p < 0.001 |
| launch_month10 | 0.1616 | 0.0231 | 7.0103 | 0.000000 | *** p < 0.001 |
| launch_month11 | 0.1138 | 0.0233 | 4.8894 | 0.000001 | *** p < 0.001 |
| launch_month12 | -0.0700 | 0.0264 | -2.6487 | 0.008081 | ** p < 0.01 |
| launch_year2010 | -0.4048 | 0.0799 | -5.0692 | 0.000000 | *** p < 0.001 |
| launch_year2011 | -0.4035 | 0.0775 | -5.2093 | 0.000000 | *** p < 0.001 |
| launch_year2012 | -0.6174 | 0.0772 | -7.9990 | 0.000000 | *** p < 0.001 |
| launch_year2013 | -0.5218 | 0.0772 | -6.7565 | 0.000000 | *** p < 0.001 |
| launch_year2014 | -0.8981 | 0.0770 | -11.6599 | 0.000000 | *** p < 0.001 |
| launch_year2015 | -0.9981 | 0.0771 | -12.9510 | 0.000000 | *** p < 0.001 |
| launch_year2016 | -0.7360 | 0.0773 | -9.5232 | 0.000000 | *** p < 0.001 |
| launch_year2017 | -0.5931 | 0.0775 | -7.6516 | 0.000000 | *** p < 0.001 |
Παρατήρηση: Αναμένεται ο στόχος χρηματοδότησης (
usd_goal_real) να έχει αρνητικό συντελεστή με υψηλή σημαντικότητα (p < 0.001): όσο υψηλότερος ο στόχος, τόσο χαμηλότερη η πιθανότητα επιτυχίας. Επίσης, η κατηγορία (main_category) αναμένεται να επηρεάζει σημαντικά το αποτέλεσμα (π.χ. Dance και Comics έχουν ιστορικά υψηλότερα ποσοστά επιτυχίας).
# type = "response" → επιστρέφει εκτιμώμενες πιθανότητες [0, 1]
predictTest <- predict(model, newdata = test, type = "response")
cat("Πρώτες 10 προβλεπόμενες πιθανότητες:\n")## Πρώτες 10 προβλεπόμενες πιθανότητες:
## 4 11 21 22 23 25 26 28 30 35
## 0.6069 0.0523 0.2115 0.6674 0.5841 0.3493 0.5412 0.3130 0.3474 0.5115
##
## Περίληψη προβλεπόμενων πιθανοτήτων:
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.0000 0.2992 0.4079 0.4038 0.5149 0.8557
Τι μας δείχνει η
predict()?
Μεtype = "response", ηpredict()επιστρέφει για κάθε καμπάνια του test set την εκτιμώμενη πιθανότητα επιτυχίας P(state = successful | X). Για παράδειγμα, τιμή 0.71 σημαίνει ότι το μοντέλο εκτιμά 71% πιθανότητα η καμπάνια να επιτύχει τον στόχο της. Οι τιμές αυτές κατηγοριοποιούνται στη συνέχεια σε 0 ή 1 βάσει κατωφλίου (threshold = 0.5).
pred_class <- ifelse(predictTest >= 0.5, 1, 0)
cm <- table(Provlepomeno = pred_class,
Pragmatiko = test$state_binary)
print(cm)## Pragmatiko
## Provlepomeno 0 1
## 0 55717 27475
## 1 13425 19389
TN <- cm["0", "0"]
FP <- cm["1", "0"]
FN <- cm["0", "1"]
TP <- cm["1", "1"]
accuracy <- (TP + TN) / sum(cm)
sensitivity <- TP / (TP + FN)
specificity <- TN / (TN + FP)
cat("╔══════════════════════════════════════════════╗\n")## ╔══════════════════════════════════════════════╗
## ║ ΑΞΙΟΛΟΓΗΣΗ ΜΟΝΤΕΛΟΥ ║
## ╠══════════════════════════════════════════════╣
## ║ True Positive (TP) : 19389 ║
## ║ True Negative (TN) : 55717 ║
## ║ False Positive (FP) : 13425 ║
## ║ False Negative (FN) : 27475 ║
## ╠══════════════════════════════════════════════╣
## ║ Ακριβεια (Accuracy) : 0.6474 ║
## ║ Sensitivity (Recall/TPR) : 0.4137 ║
## ║ Specificity (TNR) : 0.8058 ║
## ╚══════════════════════════════════════════════╝
majority_class <- names(which.max(table(test$state_binary)))
baseline_accuracy <- max(table(test$state_binary)) / nrow(test)
cat("Πλειοψηφικη κατηγορια στο test set :", majority_class, "\n")## Πλειοψηφικη κατηγορια στο test set : 0
## Ακριβεια Baseline Model : 0.596
## Ακριβεια Logistic Regression Model : 0.6474
cat("Βελτιωση εναντι Baseline :",
round((accuracy - baseline_accuracy) * 100, 2), "ποσοστιαιες μοναδες\n")## Βελτιωση εναντι Baseline : 5.14 ποσοστιαιες μοναδες
Παρατήρηση:
Το baseline model που πάντα προβλέπει την πλειοψηφική κλάση (0= failed, ~64% των καμπανιών αποτυγχάνουν) επιτυγχάνει ακρίβεια ~64%. Το μοντέλο Λογιστικής Παλινδρόμησης υπερτερεί σημαντικά, αποδεικνύοντας ότι μεταβλητές όπως ο στόχος χρηματοδότησης και η κατηγορία έχουν πραγματική προβλεπτική αξία.
# state_binary είναι ήδη integer (0/1) — prediction() λειτουργεί απευθείας
ROCRpred <- prediction(predictTest, test$state_binary)
cat("Αντικειμενο ROCRpred δημιουργηθηκε επιτυχως.\n")## Αντικειμενο ROCRpred δημιουργηθηκε επιτυχως.
## Κλαση : prediction
## Παρατηρησεις: 116006
ROCRperf <- performance(ROCRpred, "tpr", "fpr")
plot(ROCRperf,
colorize = TRUE,
print.cutoffs.at = seq(0, 1, by = 0.1),
text.adj = c(-0.2, 1.7),
main = "ROC Καμπύλη – Πρόβλεψη Επιτυχίας Kickstarter",
xlab = "False Positive Rate (1 – Specificity)",
ylab = "True Positive Rate (Sensitivity)",
lwd = 2.5)
abline(a = 0, b = 1, lty = 2, col = "gray50", lwd = 1.5)
legend("bottomright",
legend = c("ROC Καμπύλη (χρώμα = κατώφλι)", "Τυχαίος Ταξινομητής (AUC = 0.5)"),
col = c("blue", "gray50"),
lty = c(1, 2),
lwd = 2,
bty = "n")auc_val <- performance(ROCRpred, "auc")
auc <- as.numeric(auc_val@y.values)
cat("╔══════════════════════════════════════════╗\n")## ╔══════════════════════════════════════════╗
## ║ AUC = 0.6828 ║
## ╠══════════════════════════════════════════╣
## ║ Ερμηνεια: ║
if (auc >= 0.9) {
cat("║ Aristh diakritiki ikanotita ║\n")
} else if (auc >= 0.8) {
cat("║ Poly kali diakritiki ikanotita ║\n")
} else if (auc >= 0.7) {
cat("║ Kali diakritiki ikanotita ║\n")
} else {
cat("║ Metria diakritiki ikanotita ║\n")
}## ║ Metria diakritiki ikanotita ║
## ╚══════════════════════════════════════════╝
Ερμηνεία AUC:
Το AUC (Area Under the ROC Curve) εκφράζει τη συνολική διακριτική ικανότητα του μοντέλου ανεξαρτήτως κατωφλίου. Κυμαίνεται από 0.5 (τυχαία) έως 1.0 (τέλεια). Τιμή AUC > 0.70 θεωρείται καλή απόδοση για αυτό το πρόβλημα, δεδομένης της πολυπλοκότητας της επιτυχίας μιας καμπάνιας crowdfunding.
na.omit — Sets train2 & test2Επαναλαμβάνουμε την ανάλυση χρησιμοποιώντας μόνο τις πλήρεις παρατηρήσεις με
na.omit().
## Καταχωρησεις ΠΡΙΝ na.omit : 331446
## Καταχωρησεις ΜΕΤΑ na.omit: 331446
## Αφαιρεθηκαν : 0 καταχωρησεις
set.seed(942)
split2 <- sample.split(df_clean$state_binary, SplitRatio = 0.65)
train2 <- subset(df_clean, split2 == TRUE)
test2 <- subset(df_clean, split2 == FALSE)
cat("╔═══════════════════════════════════════════╗\n")## ╔═══════════════════════════════════════════╗
## ║ ΝΕΑ SETS (na.omit) ║
## ╠═══════════════════════════════════════════╣
## ║ train2 : 215440 καταχωρησεις ║
## ║ test2 : 116006 καταχωρησεις ║
## ╚═══════════════════════════════════════════╝
model2 <- glm(state_binary ~ .,
data = train2,
family = binomial(link = "logit"))
predictTest2 <- predict(model2, newdata = test2, type = "response")
pred_class2 <- ifelse(predictTest2 >= 0.5, 1, 0)
cm2 <- table(Provlepomeno = pred_class2,
Pragmatiko = test2$state_binary)
TN2 <- cm2["0", "0"]; FP2 <- cm2["1", "0"]
FN2 <- cm2["0", "1"]; TP2 <- cm2["1", "1"]
accuracy2 <- (TP2 + TN2) / sum(cm2)
sensitivity2 <- TP2 / (TP2 + FN2)
specificity2 <- TN2 / (TN2 + FP2)
ROCRpred2 <- prediction(predictTest2, test2$state_binary)
auc2 <- as.numeric(performance(ROCRpred2, "auc")@y.values)
cat("=== Αποτελεσματα Μοντελου 2 (na.omit) ===\n")## === Αποτελεσματα Μοντελου 2 (na.omit) ===
## Ακριβεια : 0.6474
## Sensitivity : 0.4137
## Specificity : 0.8058
## AUC : 0.6828
ROCRperf2 <- performance(ROCRpred2, "tpr", "fpr")
plot(ROCRperf2,
colorize = TRUE,
print.cutoffs.at = seq(0, 1, by = 0.1),
text.adj = c(-0.2, 1.7),
main = paste0("ROC Καμπύλη – Μοντέλο 2 (na.omit) | AUC = ",
round(auc2, 4)),
xlab = "False Positive Rate (1 – Specificity)",
ylab = "True Positive Rate (Sensitivity)",
lwd = 2.5)
abline(a = 0, b = 1, lty = 2, col = "gray50", lwd = 1.5)
legend("bottomright",
legend = c("ROC Καμπύλη (χρώμα = κατώφλι)", "Τυχαίος Ταξινομητής (AUC = 0.5)"),
col = c("blue", "gray50"),
lty = c(1, 2),
lwd = 2,
bty = "n")comparison <- data.frame(
Montelo = c("Μοντέλο 1 (με NA)", "Μοντέλο 2 (na.omit)", "Baseline"),
Train = c(nrow(train), nrow(train2), nrow(train)),
Test = c(nrow(test), nrow(test2), nrow(test)),
Akriveia = c(round(accuracy, 4), round(accuracy2, 4),
round(baseline_accuracy, 4)),
Sensitivity = c(round(sensitivity, 4), round(sensitivity2, 4), NA),
Specificity = c(round(specificity, 4), round(specificity2, 4), NA),
AUC = c(round(auc, 4), round(auc2, 4), 0.5000)
)
kable(comparison,
caption = "Συγκριτικός Πίνακας Μοντέλων Λογιστικής Παλινδρόμησης",
row.names = FALSE,
align = "lrrrrrr",
na = "—")| Montelo | Train | Test | Akriveia | Sensitivity | Specificity | AUC |
|---|---|---|---|---|---|---|
| Μοντέλο 1 (με NA) | 215440 | 116006 | 0.6474 | 0.4137 | 0.8058 | 0.6828 |
| Μοντέλο 2 (na.omit) | 215440 | 116006 | 0.6474 | 0.4137 | 0.8058 | 0.6828 |
| Baseline | 215440 | 116006 | 0.5960 | NA | NA | 0.5000 |
Από την ανάλυση Λογιστικής Παλινδρόμησης στο Kickstarter dataset προκύπτουν τα εξής βασικά συμπεράσματα:
Σημαντικές Μεταβλητές: Ο στόχος
χρηματοδότησης (usd_goal_real) εμφανίζει αρνητικό
συντελεστή με υψηλή σημαντικότητα (p < 0.001): υψηλότερος στόχος
μειώνει σημαντικά την πιθανότητα επιτυχίας. Η κατηγορία
(main_category) επίσης διαφοροποιείται σημαντικά —
κατηγορίες όπως Dance και Comics έχουν ιστορικά
υψηλότερα ποσοστά επιτυχίας.
Απόδοση Μοντέλου: Η ακρίβεια του μοντέλου υπερτερεί του baseline (~64%), επιβεβαιώνοντας ότι οι επιλεγμένες μεταβλητές εξηγούν μέρος της επιτυχίας μιας καμπάνιας.
AUC: Η τιμή AUC αντικατοπτρίζει τη διακριτική ικανότητα του μοντέλου. Το crowdfunding εξαρτάται και από παράγοντες που δεν υπάρχουν στο dataset (ποιότητα περιεχομένου, marketing, δίκτυο δημιουργού), οπότε ένα AUC στο 0.70–0.75 θεωρείται ικανοποιητικό.
Επίδραση na.omit: Δεδομένου ότι το
Kickstarter dataset έχει σχετικά λίγες ελλείπουσες τιμές (κυρίως στο
usd_goal_real), τα δύο μοντέλα αναμένεται να δίνουν
παρόμοια αποτελέσματα.
Sensitivity vs Specificity: Σε επιχειρηματικό πλαίσιο, υψηλό sensitivity (αναγνώριση επιτυχημένων καμπανιών) είναι χρήσιμο για επενδυτές/δημιουργούς που θέλουν να εντοπίσουν υποσχόμενα projects.
Εργασία στο πλαίσιο του μαθήματος Επιχειρηματική Αναλυτική – Τμήμα Εφαρμοσμένης Πληροφορικής, ΠΑΜΑΚ
## R Version : R version 4.5.2 (2025-10-31)
## Ημερομηνια : 20/04/2026 14:08