From 433262a16364902dc7d76e62f4035d5f076c9730 Mon Sep 17 00:00:00 2001 From: Hu Ziang Date: Mon, 28 Oct 2024 04:39:11 +0800 Subject: [PATCH] Add posts breast-cancer-prediction --- .../breast-cancer-prediction/feature.jpg | Bin 0 -> 81423 bytes .../breast-cancer-prediction/index.en.md | 630 ++++++++++++++++++ .../breast-cancer-prediction/index.zh-cn.md | 618 +++++++++++++++++ .../posts/breast-cancer-prediction/plot1.svg | 1 + .../posts/breast-cancer-prediction/plot10.svg | 1 + .../posts/breast-cancer-prediction/plot11.svg | 1 + .../posts/breast-cancer-prediction/plot2.svg | 9 + .../posts/breast-cancer-prediction/plot3.svg | 9 + .../posts/breast-cancer-prediction/plot4.svg | 9 + .../posts/breast-cancer-prediction/plot5.svg | 9 + .../posts/breast-cancer-prediction/plot6.svg | 9 + .../posts/breast-cancer-prediction/plot7.svg | 9 + .../posts/breast-cancer-prediction/plot8.svg | 1 + .../posts/breast-cancer-prediction/plot9.svg | 1 + 14 files changed, 1307 insertions(+) create mode 100644 content/posts/breast-cancer-prediction/feature.jpg create mode 100644 content/posts/breast-cancer-prediction/index.en.md create mode 100644 content/posts/breast-cancer-prediction/index.zh-cn.md create mode 100644 content/posts/breast-cancer-prediction/plot1.svg create mode 100644 content/posts/breast-cancer-prediction/plot10.svg create mode 100644 content/posts/breast-cancer-prediction/plot11.svg create mode 100644 content/posts/breast-cancer-prediction/plot2.svg create mode 100644 content/posts/breast-cancer-prediction/plot3.svg create mode 100644 content/posts/breast-cancer-prediction/plot4.svg create mode 100644 content/posts/breast-cancer-prediction/plot5.svg create mode 100644 content/posts/breast-cancer-prediction/plot6.svg create mode 100644 content/posts/breast-cancer-prediction/plot7.svg create mode 100644 content/posts/breast-cancer-prediction/plot8.svg create mode 100644 content/posts/breast-cancer-prediction/plot9.svg diff --git a/content/posts/breast-cancer-prediction/feature.jpg b/content/posts/breast-cancer-prediction/feature.jpg new file mode 100644 index 0000000000000000000000000000000000000000..498afd9829ba4a1c1a2065d503f08393919559c9 GIT binary patch literal 81423 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⪚kY?!lZVM2|n|D2FqB^(Z!v&C(n%clKqf1 zOJt~tY2N8KoZZY@+_5&>k@uMU-iPeq5NZz4M$kdw9gqgncMMBtTm3^?L9_$7f z`9{e70h&)o0&QC7G$?CtWfvmeFG4>n&wS6^%#n^?NqGDn{?ey*BE7l)0F~&jYwvQ8 zwUu~!h>Z(Zf=0_9rGsmt+6Xg%v)s2X;%a{OL$vw>DtW(?-CKhts~VIWSxMnf_HZsV ztH`fnI}cRAx{|I?A1gA* zCbXR=jP#>m-Ek6dZ3WQ51amhWA*@t7_;&g(LY$m~P1# zA8JRJFDLkTsWm^7^&7@DC4)2~Nd?4AgsICg53q`C%v%}cVt5%J+adAN614KJ3jzzJcPW8>iYQ?6=5muT*lZt^i}^OfsL=RrwC7 zr?K00Y_mo@=pS$D$@xcpWPjpqWlSV!xy05!^?y;B}Qe zC_@j;i0)ULIwYgPB8L4xlyb@j%eW$&=L4&6*!c~JCarE|w?3niKUIgwbwmP-B%*Zi zN}>M%Ir#w`c+sv&tF@{lpE@eWe`E5GOS%JOkjW7}^nAnUe~{`nr2WmxNTY~Ils`&* zhT7x}mo}?k3`|$^Q{*cJYSwpCMc@yXMg61sM`LgX*e;5b-j*}^Q{+0Wu|IhXQi0z` zDt~X}I!)IKywINkRdM;gL# Data source: [Breast Cancer Prediction Dataset](https://www.kaggle.com/datasets/merishnasuwal/breast-cancer-prediction-dataset) + +## Introduction + +Worldwide, breast cancer is the most common type of cancer in women and the second highest in terms of mortality rates.Diagnosis of breast cancer is performed when an abnormal lump is found (from self-examination or x-ray) or a tiny speck of calcium is seen (on an x-ray). After a suspicious lump is found, the doctor will conduct a diagnosis to determine whether it is cancerous and, if so, whether it has spread to other parts of the body.  + +This breast cancer dataset was obtained from the University of Wisconsin Hospitals, Madison from Dr. William H. Wolberg. + +## Import + +The first step is import the raw data to the program code. + +```R +data <- read.csv("Breast_cancer_data.csv") +``` + +Thanks to the selected raw data containing the header and the built-in function(`read.csv`) of importing *CSV files* in the R language, we only need a simple line of code to efficiently import files into our program for subsequent processing. + +Using the `head` function, we briefly view part of the data. + +```R +head(data) +``` + +```text +# mean_radius mean_texture mean_perimeter mean_area mean_smoothness diagnosis +# 1 17.99 10.38 122.80 1001.0 0.11840 0 +# 2 20.57 17.77 132.90 1326.0 0.08474 0 +# 3 19.69 21.25 130.00 1203.0 0.10960 0 +# 4 11.42 20.38 77.58 386.1 0.14250 0 +# 5 20.29 14.34 135.10 1297.0 0.10030 0 +# 6 12.45 15.70 82.57 477.1 0.12780 0 +``` + +Obviously, each piece of data in the dataset contains 5 data related to breast cancer, and 0 and 1 are used in the last column to indicate whether the diagnosis is confirmed. + +## Tidy + +Generally speaking, in order to analyze the data, we need to **clean the data** to a certain extent, separate and merge some cell data, discard some unwanted data, and amplify important data, so as to make the data more **compact** for us to modeling and analyze. + +We expect to use data to build models. For this data set, every piece of information has its utilization value, so in order to ensure that the amount of data is sufficient, we do not need to process it too much. + +### Check for missing data + +We need to judge whether there is any data missing data in the data set to avoid unforeseen errors when building the model. + +```R +sum(is.na(data)) +``` + +Fortunately, there is no data missing in our dataset, and each piece of data is complete and full of utilization value. + +### View redundant data + +First of all, we need to ensure that the data in the dataset is not duplicated to prevent interference with subsequent modeling. + +```R +duplicated_count <- sum(duplicated(data)) +``` + +Output 0, no duplicate data. + +## Analyze data + +Our goal is to establish a reasonable prediction model to achieve accurate prediction of breast cancer diagnosis through certain quantifiable data. + +### Analyze the distribution of variables + +In order to have a basic understanding of the distribution of parameters, we will map the distribution of each variable separately. + +In this case, the combination of histogram and density distribution map is the most intuitive and effective. + +Since the longitudinal axis of `geom_density()` is density estimation, in order to be able to draw the histogram and the density estimation in the same coordinate system, it is necessary to change the longitudinal axis of the histogram to density estimation. + +```R +rel_area <- ggplot(data, aes(x = mean_area, y = ..density..)) + + geom_histogram(fill = "blue", color = "black", size = 0.2, alpha = 0.2, bins = 30) + + geom_density() +rel_radius <- ggplot(data, aes(x = mean_radius, y = ..density..)) + + geom_histogram(fill = "blue", color = "black", size = 0.2, alpha = 0.2, bins = 30) + + geom_density() +rel_texture <- ggplot(data, aes(x = mean_texture, y = ..density..)) + + geom_histogram(fill = "blue", color = "black", size = 0.2, alpha = 0.2, bins = 30) + + geom_density() +rel_smooth <- ggplot(data, aes(x = mean_smoothness, y = ..density..)) + + geom_histogram(fill = "blue", color = "black", size = 0.2, alpha = 0.2, bins = 30) + + geom_density() +rel_perimeter <- ggplot(data, aes(x = mean_perimeter, y = ..density..)) + + geom_histogram(fill = "blue", color = "black", size = 0.2, alpha = 0.2, bins = 30) + + geom_density() +``` + +Finally, we use the `grid.arrange` function in the `gridExtra` library to arrange the charts together. + +```R +grid.arrange(rel_area, rel_radius, rel_texture, rel_smooth, rel_perimeter, + nrow = 3, + ncol = 2 +) +``` + +![](plot1.svg) + +We note that the distribution of all data has two properties: + +1. All data is continuously distributed in a certain interval. +2. Each data is distributed in large quantities near a value, and the farther away it is, the less distributed it will be. + +### Analysis of univariate diagnostic results + +> We analyze the correlation between each variable and the diagnostic results. Here we use the method of drawing a box pattern. + +#### mean_radius + +```R +ggplot(data, aes(x = factor(diagnosis), y = mean_radius)) + + geom_boxplot(outlier.colour = "blue", outlier.shape = 5, outlier.size = 4) + + labs(title = "Plot of mean_radius", x = "diagnosis") +``` + +![](plot2.svg) + +It can be seen that the average tumor radius of patients with breast cancer is mainly between 10 and 15, while the undiagnosed is mainly between 15 and 20. + +#### mean_texture + +```R +ggplot(data, aes(x = factor(diagnosis), y = mean_texture)) + + geom_boxplot(outlier.colour = "blue", outlier.shape = 5, outlier.size = 4) + + labs(title = "Plot of mean_texture", x = "diagnosis") +``` + +![](plot3.svg) + +It can be found that the average texture value of the patient's tumor is between 15 and 20, while that has not been diagnosed is between 20 and 25. + +#### mean_perimeter + +```R +ggplot(data, aes(x = factor(diagnosis), y = mean_perimeter)) + + geom_boxplot(outlier.colour = "blue", outlier.shape = 5, outlier.size = 4) + + labs(title = "Plot of mean_perimeter", x = "diagnosis") +``` + +![](plot4.svg) + +As can be seen from the figure, the average perimeter of tumors in confirmed patients is between 70 and 90, while those that have not been diagnosed is between 100 and 130. + +#### mean_area + +```R +ggplot(data, aes(x = factor(diagnosis), y = mean_area)) + + geom_boxplot(outlier.colour = "blue", outlier.shape = 5, outlier.size = 4) + + labs(title = "Plot of mean_area", x = "diagnosis") +``` + +![](plot5.svg) + +It can be found that the average tumor area of confirmed patients is about 500, while the main undiagnosed tumors are between 750 and 1250. + +#### mean_smoothness + +```R +ggplot(data, aes(x = factor(diagnosis), y = mean_smoothness)) + + geom_boxplot(outlier.colour = "blue", outlier.shape = 5, outlier.size = 4) + + labs(title = "Plot of mean_smoothness", x = "diagnosis") +``` + +![](plot6.svg) + +We have noticed that there is an intersection of tumor smoothness in patients with positive or negative confirmed results, but in general, the value of confirmed patients will be lower. + +### Relevance analysis + +According to the general process of modeling, we need to carry out correlation analysis of each variable. + +If the correlation between variables is significant, it will affect the predictive effect of the model. + +```R +cor_analysis <- cor(data[c(1:5)]) +corrplot(cor_analysis, method = "number") +``` + +![](plot7.svg) + +Through correlation analysis, we found that the relationship between the three variables is very significant. + +They are **radius**, **perimeter** and **area**. + +These three values are obviously highly correlated, so we need to filter them. + +### Correlation between variables and diagnostic results + +Before the final accuracy of the qualitative analysis model, we want to use the image to see the relationship between variables and diagnostic results first. There are some intuitive impressions. + +We have a total of five variables: + +1. mean_radius +2. mean_texture +3. mean_perimeter +4. mean_area +5. mean_smoothness + +The correlation between them and diagnostic results is combined, and there are a total of 10 situations that need to be discussed and analyzed. + +> The red dot in the chart below indicates that the diagnostic result is undiagnosed. + +#### Weak correlation of variables + +> radius & texture, radius & smoothness, texture & perimeter, texture & area, texture & smoothness, perimeter & smoothness, area & smoothness + +![](plot8.svg) + +We can have an intuitive understanding of the relationship between the two variables through the scatter distribution in the chart. + +#### Strong correlation of variables + +> radius & perimeter, radius & area, perimeter & area + +```R +# radius & perimeter +rpPlot <- ggplot(data, aes( + x = mean_radius, y = mean_perimeter, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +# radius & area +raPlot <- ggplot(data, aes( + x = mean_radius, y = mean_area, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +# perimeter & area +paPlot <- ggplot(data, aes( + x = mean_perimeter, y = mean_area, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +grid.arrange(rpPlot, raPlot, paPlot, + nrow = 1, + ncol = 3 +) +``` + +![](plot9.svg) + +As previously expected, they are quite relevant, and their analysis can be carried out at the same time. + +Obviously, from the chart, patients with an average tumor radius of 10 to 15 have a higher probability of being diagnosed with breast cancer. + +## Model + +### Dataset segmentation + +For subsequent modeling, we need to randomly divide the data set into two parts, one to train the prediction model, and the other to test the accuracy of the model. + +```R +set.seed(123) # Set the repeatability set.seed() to ensure that it is repeatable +train <- sample(nrow(data), 0.7 * nrow(data)) +train_data <- data[train, ] +test_data <- data[-train, ] +``` + +*train_ data* means training data, *validate_ data* stands for inspection data + +### Logistic regression modeling + +> Since the final prediction results are 0 and 1, it is not suitable to use linear regression. +> +> Here we choose to use the idea of logical regression to build a model. + +The connection function used in logical regression is the best representative of the Sigmoid function, that is, the logistic function. + +From the above analysis, we select *radius* among *radius*, *perimeter* and *area* for modeling. + +```R +model <- glm( + data = train_data, + formula = diagnosis ~ mean_texture + mean_smoothness + mean_radius, + family = binomial(link = "logit") +) +model <- step(model) # Carry out the step-by-step regression method for data analysis +summary(model) +``` + +Use `summary (model)` to view the model. + +```text +Call: +glm(formula = diagnosis ~ mean_texture + mean_smoothness + mean_radius, + family = binomial(link = "logit"), data = train_data) + +Deviance Residuals: + Min 1Q Median 3Q Max +-2.91948 -0.03436 0.04781 0.21133 2.01672 + +Coefficients: + Estimate Std. Error z value Pr(>|z|) +(Intercept) 40.52957 5.09828 7.950 1.87e-15 *** +mean_texture -0.34187 0.06622 -5.163 2.44e-07 *** +mean_smoothness -140.35265 21.54005 -6.516 7.23e-11 *** +mean_radius -1.36821 0.17827 -7.675 1.65e-14 *** +--- +Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 + +(Dispersion parameter for binomial family taken to be 1) + + Null deviance: 515.0 on 397 degrees of freedom +Residual deviance: 134.9 on 394 degrees of freedom +AIC: 142.9 + +Number of Fisher Scoring iterations: 8 +``` + +From the results of `summary`, it can be seen that the three variables we selected contribute significantly to the results. + +### Calculate the fitting threshold + +Here we use `roc` from `pRoc` to find the optimal threshold. + +```R +pre <- predict(model, type = "response", train_data) +modelroc <- roc(train_data$diagnosis, pre) +plot(modelroc, + print.auc = TRUE, auc.polygon = TRUE, + grid = c(0.1, 0.2), grid.col = c("green", "red"), + max.auc.polygon = TRUE, + auc.polygon.col = "skyblue", print.thres = TRUE +) +``` + +![](plot10.svg) + +It can be seen that 0.588 is the threshold we need. Considering it, we choose 0.6 as the threshold of the model. + +### Test Set Data Validation + +After successfully using the training set data to build a model, we should also use the check data set to check the accuracy of model prediction. + +Since the forecast is a number, and what we ultimately want is a confirmed or undiagnosed result, we need a threshold to classify the predicted value to get a numerical result of 1 or 0. + +```R +test_data$prob <- model %>% + predict(type = "response", newdata = test_data) +test_data$prob <- ifelse(test_data$prob > 0.6, 1, 0) +test_data$diff <- ifelse(test_data$diagnosis == test_data$prob, 1, 0) +``` + +### Evaluate the predictive effect of the model + +We can draw a pie chart to visualize the accuracy of the model. + +```R +diff_count <- test_data %>% + count(diff, name = "count") +diff_count$diff <- ifelse(diff_count$diff == 0, "False", "True") + +diff_plot <- diff_count %>% + ggplot(mapping = aes( + x = 1, + y = count, + fill = factor(diff), + )) + +diff_plot + + geom_bar(stat = "identity") + + coord_polar(theta = "y") + + scale_x_continuous(name = NULL, breaks = NULL) + + scale_y_continuous(name = NULL, breaks = NULL) + + labs( + x = "", y = "", + fill = "", + title = "Model prediction accuracy", + ) + + theme( + legend.position = "top", + plot.title = element_text(hjust = 0.5, size = 14), # title position + ) +``` + +![](plot11.svg) + +```R +paste( + round(100 * diff_count$count[2] / (diff_count$count[1] + diff_count$count[2]), 2), + "%" +) +``` + +```text +[1] "93.57 %" +``` + +The result was very surprising. The prediction accuracy of our model was extremely high. In order to avoid errors and remove preset random values, I tried many times and got better results of more than 90%, which shows that our model is stable and accurate. + +{{%details summary="Full code"%}} +```R +library(tidyverse) +library(ggplot2) +library(corrplot) +library(pROC) +library(gridExtra) + +# Import the original data +data <- read.csv("Breast_cancer_data.csv") +head(data) + +# Check for missing data +sum(is.na(data)) + +# Redundant data view +duplicated_count <- sum(duplicated(data)) + +# Analyze the distribution of each variable +rel_area <- ggplot(data, aes(x = mean_area, y = ..density..)) + + geom_histogram(fill = "blue", color = "black", size = 0.2, alpha = 0.2, bins = 30) + # nolint + geom_density() +rel_radius <- ggplot(data, aes(x = mean_radius, y = ..density..)) + + geom_histogram(fill = "blue", color = "black", size = 0.2, alpha = 0.2, bins = 30) + # nolint + geom_density() +rel_texture <- ggplot(data, aes(x = mean_texture, y = ..density..)) + + geom_histogram(fill = "blue", color = "black", size = 0.2, alpha = 0.2, bins = 30) + # nolint + geom_density() +rel_smooth <- ggplot(data, aes(x = mean_smoothness, y = ..density..)) + + geom_histogram(fill = "blue", color = "black", size = 0.2, alpha = 0.2, bins = 30) + # nolint + geom_density() +rel_perimeter <- ggplot(data, aes(x = mean_perimeter, y = ..density..)) + + geom_histogram(fill = "blue", color = "black", size = 0.2, alpha = 0.2, bins = 30) + # nolint + geom_density() +grid.arrange(rel_area, rel_radius, rel_texture, rel_smooth, rel_perimeter, + nrow = 3, + ncol = 2 +) + +# Univariate box pattern analysis +# mean_radius +ggplot(data, aes(x = factor(diagnosis), y = mean_radius)) + + geom_boxplot(outlier.colour = "blue", outlier.shape = 5, outlier.size = 4) + + labs(title = "Plot of mean_radius", x = "diagnosis") +# mean_texture +ggplot(data, aes(x = factor(diagnosis), y = mean_texture)) + + geom_boxplot(outlier.colour = "blue", outlier.shape = 5, outlier.size = 4) + + labs(title = "Plot of mean_texture", x = "diagnosis") +# mean_perimeter +ggplot(data, aes(x = factor(diagnosis), y = mean_perimeter)) + + geom_boxplot(outlier.colour = "blue", outlier.shape = 5, outlier.size = 4) + + labs(title = "Plot of mean_perimeter", x = "diagnosis") +# mean_area +ggplot(data, aes(x = factor(diagnosis), y = mean_area)) + + geom_boxplot(outlier.colour = "blue", outlier.shape = 5, outlier.size = 4) + + labs(title = "Plot of mean_area", x = "diagnosis") +# mean_smoothness +ggplot(data, aes(x = factor(diagnosis), y = mean_smoothness)) + + geom_boxplot(outlier.colour = "blue", outlier.shape = 5, outlier.size = 4) + + labs(title = "Plot of mean_smoothness", x = "diagnosis") + +# Correlation analysis between variables +cor_analysis <- cor(data[c(1:5)]) +corrplot(cor_analysis, method = "number") + +# Relevance between variables and results +# ----------------------------Related variables------------------------------ # +# radius & texture +rtPlot <- ggplot(data, aes( + x = mean_radius, y = mean_texture, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +# radius & smoothness +rsPlot <- ggplot(data, aes( + x = mean_radius, y = mean_smoothness, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +# texture & perimeter +tpPlot <- ggplot(data, aes( + x = mean_texture, y = mean_perimeter, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +# texture & area +taPlot <- ggplot(data, aes( + x = mean_texture, y = mean_area, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +# texture & smoothness +tsPlot <- ggplot(data, aes( + x = mean_texture, y = mean_smoothness, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +# perimeter & smoothness +psPlot <- ggplot(data, aes( + x = mean_perimeter, y = mean_smoothness, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +# area & smoothness +asPlot <- ggplot(data, aes( + x = mean_area, y = mean_smoothness, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +grid.arrange(rtPlot, rsPlot, tpPlot, taPlot, tsPlot, psPlot, asPlot, + nrow = 3, + ncol = 3 +) +# ---------------------------Strong related variable---------------------------- # +# radius & perimeter +rpPlot <- ggplot(data, aes( + x = mean_radius, y = mean_perimeter, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +# radius & area +raPlot <- ggplot(data, aes( + x = mean_radius, y = mean_area, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +# perimeter & area +paPlot <- ggplot(data, aes( + x = mean_perimeter, y = mean_area, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +grid.arrange(rpPlot, raPlot, paPlot, + nrow = 1, + ncol = 3 +) + +# Dataset segmentation +set.seed(123) # Set the repeatable set.seed() to ensure that it is repeatable +train <- sample(nrow(data), 0.7 * nrow(data)) +train_data <- data[train, ] +test_data <- data[-train, ] + +# Logical regression modeling +model <- glm( + data = train_data, + formula = diagnosis ~ mean_texture + mean_smoothness + mean_radius, + family = binomial(link = "logit") +) +model <- step(model) # step-by-step regression method +summary(model) # Export all results + +# Calculate the fitting threshold +pre <- predict(model, type = "response", train_data) +modelroc <- roc(train_data$diagnosis, pre) +plot(modelroc, + print.auc = TRUE, auc.polygon = TRUE, + grid = c(0.1, 0.2), grid.col = c("green", "red"), + max.auc.polygon = TRUE, + auc.polygon.col = "skyblue", print.thres = TRUE +) + +# Test set data verification +test_data$prob <- model %>% + predict(type = "response", newdata = test_data) +test_data$prob <- ifelse(test_data$prob > 0.6, 1, 0) +test_data$diff <- ifelse(test_data$diagnosis == test_data$prob, 1, 0) + +# Test set data forecast statistics percentage +diff_count <- test_data %>% + count(diff, name = "count") +diff_count$diff <- ifelse(diff_count$diff == 0, "False", "True") + +diff_plot <- diff_count %>% + ggplot(mapping = aes( + x = 1, + y = count, + fill = factor(diff), + )) + +diff_plot + + geom_bar(stat = "identity") + + coord_polar(theta = "y") + + scale_x_continuous(name = NULL, breaks = NULL) + + scale_y_continuous(name = NULL, breaks = NULL) + + labs( + x = "", y = "", + fill = "", + title = "Model prediction accuracy", + ) + + theme( + legend.position = "top", + plot.title = element_text(hjust = 0.5, size = 14), + ) + +paste( + round(100 * diff_count$count[2] / (diff_count$count[1] + diff_count$count[2]), 2), + "%" +) +``` +{{%/details%}} \ No newline at end of file diff --git a/content/posts/breast-cancer-prediction/index.zh-cn.md b/content/posts/breast-cancer-prediction/index.zh-cn.md new file mode 100644 index 0000000..26ec3bb --- /dev/null +++ b/content/posts/breast-cancer-prediction/index.zh-cn.md @@ -0,0 +1,618 @@ +--- +title: "乳腺癌预测模型" +date: 2022-06-22T01:23:48+08:00 +tags: ["数据分析", "R语言"] +series: ["R语言数据分析"] +series_order: 4 +--- + +> 数据来源:[乳腺癌预测数据集](https://www.kaggle.com/datasets/merishnasuwal/breast-cancer-prediction-dataset) + +## 简介 + +全球范围内,乳腺癌是女性最常见的癌症类型,在死亡率方面排名第二。当发现异常肿块(来自自我检查或X光)或看到钙质小点(在X光片上)时,就会进行乳腺癌的诊断。在发现可疑肿块后,医生将进行诊断以确定是否为癌症,如果是,是否已扩散到身体的其他部位。 + +此乳腺癌数据集是从威斯康星大学麦迪逊分校的威廉·H·沃尔伯格博士处获得的。 + +## 导入 + +第一步是将原始数据导入程序代码。 + +```R +data <- read.csv("Breast_cancer_data.csv") +``` + +原始数据包含标题,使用R语言中导入*CSV文件*的内置函数(`read.csv`),只需一行简单的代码即可高效地将文件导入我们的程序进行后续处理。 + +使用`head`函数,我们可以简要查看数据的一部分。 + +```R +head(data) +``` + +```text +# mean_radius mean_texture mean_perimeter mean_area mean_smoothness diagnosis +# 1 17.99 10.38 122.80 1001.0 0.11840 0 +# 2 20.57 17.77 132.90 1326.0 0.08474 0 +# 3 19.69 21.25 130.00 1203.0 0.10960 0 +# 4 11.42 20.38 77.58 386.1 0.14250 0 +# 5 20.29 14.34 135.10 1297.0 0.10030 0 +# 6 12.45 15.70 82.57 477.1 0.12780 0 +``` + +显然,数据集中每条数据包含5个与乳腺癌相关的数据,最后列使用0和1来表示是否确诊。 + +## 清洗数据 + +一般来说,为了分析数据,我们需要在一定程度上**清洗数据**,分离和合并一些单元格数据,丢弃一些不需要的数据,并放大重要数据,以便使数据对我们建模和分析更加**紧凑**。 + +我们期望使用数据来构建模型。对这个数据集,每条信息都有其利用价值,因此为了确保数据量充足,我们不需要对其进行过多处理。 + +### 检查缺失数据 + +我们需要判断数据集中是否存在缺失数据,以避免在构建模型时出现未预见的错误。 + +```R +sum(is.na(data)) +``` + +幸运的是,我们的数据集中没有缺失数据,每一份数据都是完整且充满利用价值的。 + +### 查看冗余数据 + +首先,我们需要确保数据集中的数据没有重复,以防止对后续建模造成干扰。 + +```R +duplicated_count <- sum(duplicated(data)) +``` + +输出 0,无重复数据。 + +## 分析数据 + +我们的目标是建立一个合理的预测模型,通过某些可量化数据实现乳腺癌诊断的准确预测。 + +### 分析变量分布 + +为了对参数分布有一个基本了解,我们将分别映射每个变量的分布。在这种情况下,直方图和密度分布图的组合是最直观和有效的。由于`geom_density()`的纵向轴是密度估计,为了能够在同一坐标系中绘制直方图和密度估计,有必要将直方图的纵向轴改为密度估计。 + +```R +rel_area <- ggplot(data, aes(x = mean_area, y = ..density..)) + + geom_histogram(fill = "blue", color = "black", size = 0.2, alpha = 0.2, bins = 30) + + geom_density() +rel_radius <- ggplot(data, aes(x = mean_radius, y = ..density..)) + + geom_histogram(fill = "blue", color = "black", size = 0.2, alpha = 0.2, bins = 30) + + geom_density() +rel_texture <- ggplot(data, aes(x = mean_texture, y = ..density..)) + + geom_histogram(fill = "blue", color = "black", size = 0.2, alpha = 0.2, bins = 30) + + geom_density() +rel_smooth <- ggplot(data, aes(x = mean_smoothness, y = ..density..)) + + geom_histogram(fill = "blue", color = "black", size = 0.2, alpha = 0.2, bins = 30) + + geom_density() +rel_perimeter <- ggplot(data, aes(x = mean_perimeter, y = ..density..)) + + geom_histogram(fill = "blue", color = "black", size = 0.2, alpha = 0.2, bins = 30) + + geom_density() +``` + +最后,我们使用`gridExtra`库中的`grid.arrange`函数将图表排列在一起。 + +```R +grid.arrange(rel_area, rel_radius, rel_texture, rel_smooth, rel_perimeter, + nrow = 3, + ncol = 2 +) +``` + +![](plot1.svg) + +我们注意到所有数据的分布有两个特性: + +1. 所有数据在某个区间内连续分布。 +2. 每个数据在某个值附近大量分布,距离越远,分布越少。 + +### 单变量诊断结果分析 + +> 分析每个变量与诊断结果之间的相关性,使用绘制箱形图的方法 + +#### 平均半径 + +```R +ggplot(data, aes(x = factor(diagnosis), y = mean_radius)) + + geom_boxplot(outlier.colour = "blue", outlier.shape = 5, outlier.size = 4) + + labs(title = "Plot of mean_radius", x = "diagnosis") +``` + +![](plot2.svg) + +乳腺癌患者的平均肿瘤半径主要在10至15之间,而未诊断的患者主要在15至20之间。 + +#### 平均纹理 + +```R +ggplot(data, aes(x = factor(diagnosis), y = mean_texture)) + + geom_boxplot(outlier.colour = "blue", outlier.shape = 5, outlier.size = 4) + + labs(title = "Plot of mean_texture", x = "diagnosis") +``` + +![](plot3.svg) + +可以发现在患者的肿瘤中,平均纹理值介于15到20之间,而尚未被诊断的肿瘤则介于20到25之间。 + +#### 平均周长 + +```R +ggplot(data, aes(x = factor(diagnosis), y = mean_perimeter)) + + geom_boxplot(outlier.colour = "blue", outlier.shape = 5, outlier.size = 4) + + labs(title = "Plot of mean_perimeter", x = "diagnosis") +``` + +![](plot4.svg) + +如图所示,确诊患者肿瘤的平均周长在70至90之间,而未诊断的患者在100至130之间。 + +#### 平均面积 + +```R +ggplot(data, aes(x = factor(diagnosis), y = mean_area)) + + geom_boxplot(outlier.colour = "blue", outlier.shape = 5, outlier.size = 4) + + labs(title = "Plot of mean_area", x = "diagnosis") +``` + +![](plot5.svg) + +可以发现在确诊患者的平均肿瘤面积约为500,而主要未诊断的肿瘤在750到1250之间。 + +#### 平均平滑度 + +```R +ggplot(data, aes(x = factor(diagnosis), y = mean_smoothness)) + + geom_boxplot(outlier.colour = "blue", outlier.shape = 5, outlier.size = 4) + + labs(title = "Plot of mean_smoothness", x = "diagnosis") +``` + +![](plot6.svg) + +我们注意到,在阳性或阴性确认结果的病人中存在肿瘤平滑度的交集,但总体而言,确认病人的数值将会更低。 + +### 相关性分析 + +根据建模的一般过程,我们需要对每个变量进行相关性分析。如果变量之间的相关性显著,它将影响模型的预测效果。 + +```R +cor_analysis <- cor(data[c(1:5)]) +corrplot(cor_analysis, method = "number") +``` + +![](plot7.svg) + +通过相关性分析,我们发现这三个变量之间的关系非常显著。它们是**半径**、**周长**和**面积**。这三个值显然高度相关,因此我们需要对它们进行筛选。 + +### 变量与诊断结果的相关性 + +在定性分析模型最终精度之前,我们想先通过图像看看变量和诊断结果之间的关系。有一些直观的印象。 + +我们有总共五个变量: + +1. mean_radius +2. mean_texture +3. mean_perimeter +4. mean_area +5. mean_smoothness + +它们与诊断结果之间的相关性被结合,总共有10种情况需要讨论和分析。 + +> 下图中红色圆点表示诊断结果为未诊断 + +#### 变量之间的弱相关性 + +> radius & texture, radius & smoothness, texture & perimeter, texture & area, texture & smoothness, perimeter & smoothness, area & smoothness + +![](plot8.svg) + +我们可以通过图表中的散点分布直观地理解两个变量之间的关系。 + +#### 变量之间强相关性 + +> radius & perimeter, radius & area, perimeter & area + +```R +# radius & perimeter +rpPlot <- ggplot(data, aes( + x = mean_radius, y = mean_perimeter, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +# radius & area +raPlot <- ggplot(data, aes( + x = mean_radius, y = mean_area, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +# perimeter & area +paPlot <- ggplot(data, aes( + x = mean_perimeter, y = mean_area, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +grid.arrange(rpPlot, raPlot, paPlot, + nrow = 1, + ncol = 3 +) +``` + +![](plot9.svg) + +如先前预期的那样,它们相当相关,并且可以同时进行分析。 + +显然,从图表中可以看出,平均肿瘤半径为10至15毫米的患者被诊断为乳腺癌的概率更高。 + +## 模型 + +### 数据集分割 + +对于后续建模,我们需要将数据集随机分为两部分,一部分用于训练预测模型,另一部分用于测试模型的准确性。 + +```R +set.seed(123) # Set the repeatability set.seed() to ensure that it is repeatable +train <- sample(nrow(data), 0.7 * nrow(data)) +train_data <- data[train, ] +test_data <- data[-train, ] +``` + +*train_data* 表示训练数据,*validate_data* 代表验证数据 + +### 逻辑回归建模 + +> 由于最终预测结果是0和1,因此不适宜使用线性回归 +> +> 这里我们选择使用逻辑回归的思想来构建模型 + +逻辑回归中使用的连接函数是Sigmoid函数的最佳代表,即逻辑函数。 + +从上述分析中,我们选择 *radius* 在 *radius*、*perimeter* 和 *area* 中用于建模。 + +```R +model <- glm( + data = train_data, + formula = diagnosis ~ mean_texture + mean_smoothness + mean_radius, + family = binomial(link = "logit") +) +model <- step(model) # Carry out the step-by-step regression method for data analysis +summary(model) +``` + +Use `summary (model)` to view the model. + +```text +Call: +glm(formula = diagnosis ~ mean_texture + mean_smoothness + mean_radius, + family = binomial(link = "logit"), data = train_data) + +Deviance Residuals: + Min 1Q Median 3Q Max +-2.91948 -0.03436 0.04781 0.21133 2.01672 + +Coefficients: + Estimate Std. Error z value Pr(>|z|) +(Intercept) 40.52957 5.09828 7.950 1.87e-15 *** +mean_texture -0.34187 0.06622 -5.163 2.44e-07 *** +mean_smoothness -140.35265 21.54005 -6.516 7.23e-11 *** +mean_radius -1.36821 0.17827 -7.675 1.65e-14 *** +--- +Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 + +(Dispersion parameter for binomial family taken to be 1) + + Null deviance: 515.0 on 397 degrees of freedom +Residual deviance: 134.9 on 394 degrees of freedom +AIC: 142.9 + +Number of Fisher Scoring iterations: 8 +``` + +From the results of `summary`, it can be seen that the three variables we selected contribute significantly to the results. + +### Calculate the fitting threshold + +Here we use `roc` from `pRoc` to find the optimal threshold. + +```R +pre <- predict(model, type = "response", train_data) +modelroc <- roc(train_data$diagnosis, pre) +plot(modelroc, + print.auc = TRUE, auc.polygon = TRUE, + grid = c(0.1, 0.2), grid.col = c("green", "red"), + max.auc.polygon = TRUE, + auc.polygon.col = "skyblue", print.thres = TRUE +) +``` + +![](plot10.svg) + +可以看出0.588是我们需要的阈值。考虑到这一点,我们选择0.6作为模型的阈值。 + +### 测试集数据验证 + +在成功使用训练集数据构建模型后,我们还应该使用检查数据集来检查模型预测的准确性。由于预测是一个数字,而我们最终想要的是一个已确认或未诊断的结果,我们需要一个阈值来将预测值分类,以获得1或0的数值结果。 + +```R +test_data$prob <- model %>% + predict(type = "response", newdata = test_data) +test_data$prob <- ifelse(test_data$prob > 0.6, 1, 0) +test_data$diff <- ifelse(test_data$diagnosis == test_data$prob, 1, 0) +``` + +### 评估模型的预测效果 + +我们可以绘制饼图来可视化模型的准确率。 + +```R +diff_count <- test_data %>% + count(diff, name = "count") +diff_count$diff <- ifelse(diff_count$diff == 0, "False", "True") + +diff_plot <- diff_count %>% + ggplot(mapping = aes( + x = 1, + y = count, + fill = factor(diff), + )) + +diff_plot + + geom_bar(stat = "identity") + + coord_polar(theta = "y") + + scale_x_continuous(name = NULL, breaks = NULL) + + scale_y_continuous(name = NULL, breaks = NULL) + + labs( + x = "", y = "", + fill = "", + title = "Model prediction accuracy", + ) + + theme( + legend.position = "top", + plot.title = element_text(hjust = 0.5, size = 14), # title position + ) +``` + +![](plot11.svg) + +```R +paste( + round(100 * diff_count$count[2] / (diff_count$count[1] + diff_count$count[2]), 2), + "%" +) +``` + +```text +[1] "93.57 %" +``` + +结果非常令人惊讶。我们模型的预测准确度极高。为了避免错误和移除预设的随机值,我尝试了许多次,并得到了超过90%的更好结果,这表明我们的模型稳定且准确。 + +{{%details summary="Full code"%}} +```R +library(tidyverse) +library(ggplot2) +library(corrplot) +library(pROC) +library(gridExtra) + +# Import the original data +data <- read.csv("Breast_cancer_data.csv") +head(data) + +# Check for missing data +sum(is.na(data)) + +# Redundant data view +duplicated_count <- sum(duplicated(data)) + +# Analyze the distribution of each variable +rel_area <- ggplot(data, aes(x = mean_area, y = ..density..)) + + geom_histogram(fill = "blue", color = "black", size = 0.2, alpha = 0.2, bins = 30) + # nolint + geom_density() +rel_radius <- ggplot(data, aes(x = mean_radius, y = ..density..)) + + geom_histogram(fill = "blue", color = "black", size = 0.2, alpha = 0.2, bins = 30) + # nolint + geom_density() +rel_texture <- ggplot(data, aes(x = mean_texture, y = ..density..)) + + geom_histogram(fill = "blue", color = "black", size = 0.2, alpha = 0.2, bins = 30) + # nolint + geom_density() +rel_smooth <- ggplot(data, aes(x = mean_smoothness, y = ..density..)) + + geom_histogram(fill = "blue", color = "black", size = 0.2, alpha = 0.2, bins = 30) + # nolint + geom_density() +rel_perimeter <- ggplot(data, aes(x = mean_perimeter, y = ..density..)) + + geom_histogram(fill = "blue", color = "black", size = 0.2, alpha = 0.2, bins = 30) + # nolint + geom_density() +grid.arrange(rel_area, rel_radius, rel_texture, rel_smooth, rel_perimeter, + nrow = 3, + ncol = 2 +) + +# Univariate box pattern analysis +# mean_radius +ggplot(data, aes(x = factor(diagnosis), y = mean_radius)) + + geom_boxplot(outlier.colour = "blue", outlier.shape = 5, outlier.size = 4) + + labs(title = "Plot of mean_radius", x = "diagnosis") +# mean_texture +ggplot(data, aes(x = factor(diagnosis), y = mean_texture)) + + geom_boxplot(outlier.colour = "blue", outlier.shape = 5, outlier.size = 4) + + labs(title = "Plot of mean_texture", x = "diagnosis") +# mean_perimeter +ggplot(data, aes(x = factor(diagnosis), y = mean_perimeter)) + + geom_boxplot(outlier.colour = "blue", outlier.shape = 5, outlier.size = 4) + + labs(title = "Plot of mean_perimeter", x = "diagnosis") +# mean_area +ggplot(data, aes(x = factor(diagnosis), y = mean_area)) + + geom_boxplot(outlier.colour = "blue", outlier.shape = 5, outlier.size = 4) + + labs(title = "Plot of mean_area", x = "diagnosis") +# mean_smoothness +ggplot(data, aes(x = factor(diagnosis), y = mean_smoothness)) + + geom_boxplot(outlier.colour = "blue", outlier.shape = 5, outlier.size = 4) + + labs(title = "Plot of mean_smoothness", x = "diagnosis") + +# Correlation analysis between variables +cor_analysis <- cor(data[c(1:5)]) +corrplot(cor_analysis, method = "number") + +# Relevance between variables and results +# ----------------------------Related variables------------------------------ # +# radius & texture +rtPlot <- ggplot(data, aes( + x = mean_radius, y = mean_texture, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +# radius & smoothness +rsPlot <- ggplot(data, aes( + x = mean_radius, y = mean_smoothness, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +# texture & perimeter +tpPlot <- ggplot(data, aes( + x = mean_texture, y = mean_perimeter, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +# texture & area +taPlot <- ggplot(data, aes( + x = mean_texture, y = mean_area, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +# texture & smoothness +tsPlot <- ggplot(data, aes( + x = mean_texture, y = mean_smoothness, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +# perimeter & smoothness +psPlot <- ggplot(data, aes( + x = mean_perimeter, y = mean_smoothness, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +# area & smoothness +asPlot <- ggplot(data, aes( + x = mean_area, y = mean_smoothness, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +grid.arrange(rtPlot, rsPlot, tpPlot, taPlot, tsPlot, psPlot, asPlot, + nrow = 3, + ncol = 3 +) +# ---------------------------Strong related variable---------------------------- # +# radius & perimeter +rpPlot <- ggplot(data, aes( + x = mean_radius, y = mean_perimeter, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +# radius & area +raPlot <- ggplot(data, aes( + x = mean_radius, y = mean_area, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +# perimeter & area +paPlot <- ggplot(data, aes( + x = mean_perimeter, y = mean_area, + color = as.factor(diagnosis) +)) + + geom_point() + + theme_minimal() + + theme(legend.position = "none") +grid.arrange(rpPlot, raPlot, paPlot, + nrow = 1, + ncol = 3 +) + +# Dataset segmentation +set.seed(123) # Set the repeatable set.seed() to ensure that it is repeatable +train <- sample(nrow(data), 0.7 * nrow(data)) +train_data <- data[train, ] +test_data <- data[-train, ] + +# Logical regression modeling +model <- glm( + data = train_data, + formula = diagnosis ~ mean_texture + mean_smoothness + mean_radius, + family = binomial(link = "logit") +) +model <- step(model) # step-by-step regression method +summary(model) # Export all results + +# Calculate the fitting threshold +pre <- predict(model, type = "response", train_data) +modelroc <- roc(train_data$diagnosis, pre) +plot(modelroc, + print.auc = TRUE, auc.polygon = TRUE, + grid = c(0.1, 0.2), grid.col = c("green", "red"), + max.auc.polygon = TRUE, + auc.polygon.col = "skyblue", print.thres = TRUE +) + +# Test set data verification +test_data$prob <- model %>% + predict(type = "response", newdata = test_data) +test_data$prob <- ifelse(test_data$prob > 0.6, 1, 0) +test_data$diff <- ifelse(test_data$diagnosis == test_data$prob, 1, 0) + +# Test set data forecast statistics percentage +diff_count <- test_data %>% + count(diff, name = "count") +diff_count$diff <- ifelse(diff_count$diff == 0, "False", "True") + +diff_plot <- diff_count %>% + ggplot(mapping = aes( + x = 1, + y = count, + fill = factor(diff), + )) + +diff_plot + + geom_bar(stat = "identity") + + coord_polar(theta = "y") + + scale_x_continuous(name = NULL, breaks = NULL) + + scale_y_continuous(name = NULL, breaks = NULL) + + labs( + x = "", y = "", + fill = "", + title = "Model prediction accuracy", + ) + + theme( + legend.position = "top", + plot.title = element_text(hjust = 0.5, size = 14), + ) + +paste( + round(100 * diff_count$count[2] / (diff_count$count[1] + diff_count$count[2]), 2), + "%" +) +``` +{{%/details%}} \ No newline at end of file diff --git a/content/posts/breast-cancer-prediction/plot1.svg b/content/posts/breast-cancer-prediction/plot1.svg new file mode 100644 index 0000000..9ba53c1 --- /dev/null +++ b/content/posts/breast-cancer-prediction/plot1.svg @@ -0,0 +1 @@ +0.00000.00050.00100.00150.002005001000150020002500mean_areadensity0.000.050.100.1510152025mean_radiusdensity0.0000.0250.0500.0750.10010203040mean_texturedensity01020300.0500.0750.1000.1250.150mean_smoothnessdensity0.0000.0050.0100.0150.0204080120160mean_perimeterdensity \ No newline at end of file diff --git a/content/posts/breast-cancer-prediction/plot10.svg b/content/posts/breast-cancer-prediction/plot10.svg new file mode 100644 index 0000000..4b406c4 --- /dev/null +++ b/content/posts/breast-cancer-prediction/plot10.svg @@ -0,0 +1 @@ +SpecificitySensitivity1.00.80.60.40.20.00.00.20.40.60.81.00.588 (0.921, 0.946)AUC: 0.979 \ No newline at end of file diff --git a/content/posts/breast-cancer-prediction/plot11.svg b/content/posts/breast-cancer-prediction/plot11.svg new file mode 100644 index 0000000..1199a0b --- /dev/null +++ b/content/posts/breast-cancer-prediction/plot11.svg @@ -0,0 +1 @@ +FalseTrueModel prediction accuracy \ No newline at end of file diff --git a/content/posts/breast-cancer-prediction/plot2.svg b/content/posts/breast-cancer-prediction/plot2.svg new file mode 100644 index 0000000..eff7152 --- /dev/null +++ b/content/posts/breast-cancer-prediction/plot2.svg @@ -0,0 +1,9 @@ +1015202501diagnosismean_radiusPlot of mean_radius \ No newline at end of file diff --git a/content/posts/breast-cancer-prediction/plot3.svg b/content/posts/breast-cancer-prediction/plot3.svg new file mode 100644 index 0000000..36df306 --- /dev/null +++ b/content/posts/breast-cancer-prediction/plot3.svg @@ -0,0 +1,9 @@ +1020304001diagnosismean_texturePlot of mean_texture \ No newline at end of file diff --git a/content/posts/breast-cancer-prediction/plot4.svg b/content/posts/breast-cancer-prediction/plot4.svg new file mode 100644 index 0000000..6e1d281 --- /dev/null +++ b/content/posts/breast-cancer-prediction/plot4.svg @@ -0,0 +1,9 @@ +408012016001diagnosismean_perimeterPlot of mean_perimeter \ No newline at end of file diff --git a/content/posts/breast-cancer-prediction/plot5.svg b/content/posts/breast-cancer-prediction/plot5.svg new file mode 100644 index 0000000..da17131 --- /dev/null +++ b/content/posts/breast-cancer-prediction/plot5.svg @@ -0,0 +1,9 @@ +500100015002000250001diagnosismean_areaPlot of mean_area \ No newline at end of file diff --git a/content/posts/breast-cancer-prediction/plot6.svg b/content/posts/breast-cancer-prediction/plot6.svg new file mode 100644 index 0000000..22c44fb --- /dev/null +++ b/content/posts/breast-cancer-prediction/plot6.svg @@ -0,0 +1,9 @@ +0.0500.0750.1000.1250.15001diagnosismean_smoothnessPlot of mean_smoothness \ No newline at end of file diff --git a/content/posts/breast-cancer-prediction/plot7.svg b/content/posts/breast-cancer-prediction/plot7.svg new file mode 100644 index 0000000..b44b0f8 --- /dev/null +++ b/content/posts/breast-cancer-prediction/plot7.svg @@ -0,0 +1,9 @@ +1.000.321.000.990.170.321.000.330.32-0.021.000.331.000.990.210.990.320.991.000.180.17-0.020.210.181.00-1-0.8-0.6-0.4-0.200.20.40.60.81mean_radiusmean_texturemean_perimetermean_areamean_smoothnessmean_radiusmean_texturemean_perimetermean_areamean_smoothness \ No newline at end of file diff --git a/content/posts/breast-cancer-prediction/plot8.svg b/content/posts/breast-cancer-prediction/plot8.svg new file mode 100644 index 0000000..d4077ce --- /dev/null +++ b/content/posts/breast-cancer-prediction/plot8.svg @@ -0,0 +1 @@ +1020304010152025mean_radiusmean_texture0.0500.0750.1000.1250.15010152025mean_radiusmean_smoothness408012016010203040mean_texturemean_perimeter500100015002000250010203040mean_texturemean_area0.0500.0750.1000.1250.15010203040mean_texturemean_smoothness0.0500.0750.1000.1250.1504080120160mean_perimetermean_smoothness0.0500.0750.1000.1250.1505001000150020002500mean_areamean_smoothness \ No newline at end of file diff --git a/content/posts/breast-cancer-prediction/plot9.svg b/content/posts/breast-cancer-prediction/plot9.svg new file mode 100644 index 0000000..dd6e37c --- /dev/null +++ b/content/posts/breast-cancer-prediction/plot9.svg @@ -0,0 +1 @@ +408012016010152025mean_radiusmean_perimeter500100015002000250010152025mean_radiusmean_area50010001500200025004080120160mean_perimetermean_area \ No newline at end of file