R interfaces, data import and export, data types, descriptive statistics, EDA and unstructured data, with Labs 1–3.
R is a free, open-source programming language and environment designed for statistical computing, data analysis and graphics. It was created by Ross Ihaka and Robert Gentleman at the University of Auckland as an open implementation of the S language, and it is maintained by the R Core Team. R's strength lies in its huge library of add-on packages — more than 20,000 on CRAN, the Comprehensive R Archive Network — covering everything from regression and machine learning to text mining and maps. R works with objects: every value, dataset, model and function is an object stored in memory, and analysis proceeds by applying functions to objects. This chapter introduces the R environment and the core skills used in every lab: importing data, understanding data types, describing data, exploring and visualising it, and handling unstructured data. It ends with the three R fundamentals labs. (Introduction to R belongs to syllabus Unit V, but it is placed early so that it is read before the labs.)
2.1 R graphical user interfaces
R can be used from a plain command line, but most users work through a graphical user interface (GUI) or an integrated development environment (IDE). The R console (RGui), installed with R on Windows and macOS, provides a basic window where commands are typed and results printed. RStudio (developed by Posit) is the most popular IDE; its four panes show the script editor, the console, the environment and history, and a pane for files, plots, packages and help. R Commander (Rcmdr) is a menu-driven GUI, installed as a package, that lets beginners run common statistical procedures without writing code while showing the equivalent R commands. Rattle is a GUI package focused on data mining, offering point-and-click data loading, exploration, model building and evaluation. Jupyter Notebook and R Markdown / Quarto documents combine code, output and explanatory text in one file, which is ideal for reproducible reports.
| Interface | Type | Best for |
|---|---|---|
| R console (RGui) | Basic GUI | Quick commands, learning syntax |
| RStudio | IDE | Everyday analysis and development |
| R Commander | Menu-driven GUI | Beginners, introductory statistics |
| Rattle | Data-mining GUI | Point-and-click modelling |
| Jupyter / R Markdown | Notebook | Reproducible reports and teaching |
2.2 Data import and export
Analysis starts by bringing data into R and ends by saving results. Data is usually loaded into a data frame, R's table structure with rows as observations and columns as variables. Base R reads delimited text with read.csv() and read.table(), and writes it with write.csv() and write.table(). The readxl package reads Excel files with read_excel(), and writexl writes them. R's own binary formats keep objects exactly as they are: saveRDS()/readRDS() store a single object and save()/load() store several. Data in databases is reached through the DBI package with a driver (RSQLite, RMySQL, RPostgres), web data through rvest (scraping) and httr/jsonlite (APIs), and statistical-package files through haven (SPSS, Stata, SAS). After import, the data should always be checked with str(), head() and summary().
students <- read.csv("students.csv") # import
str(students) # e.g. 5 obs. of 3 variables
dim(students) # 5 3
students$grade <- ifelse(students$marks >= 75, "A", "B")
write.csv(students, "students_graded.csv", row.names = FALSE) # export
saveRDS(students, "students.rds") # exact R copy
Worked example – checking an import. A CSV file has 1,250 lines including the header. After read.csv(), dim() should return 1,249 rows. If the file has 6 columns but dim() shows only 1 column, the separator is wrong (for example, a semicolon-separated file read as comma-separated), and the file must be re-read with read.csv2() or sep = ";".
2.3 Attribute and data types
Two ideas of "type" matter in R. The first is the measurement type of an attribute, which decides which calculations are meaningful. Nominal attributes are labels without order (city, blood group). Ordinal attributes have an order but no fixed interval (grade A > B > C). Interval attributes have equal intervals but no true zero (temperature in °C, calendar year), so differences are meaningful but ratios are not. Ratio attributes have a true zero (height, income, temperature in kelvin), so ratios are meaningful too. The second idea is the R data type that stores the values. R's basic types are numeric (double), integer, character, logical (TRUE/FALSE), complex and raw. These are organised into data structures: a vector (values of one type), a matrix (2-D, one type), an array (n-D, one type), a list (elements of any types), a data frame (a list of equal-length column vectors, the standard table), and a factor (a categorical variable with defined levels, which may be ordered).
x <- c(12.5, 7, 3) ; class(x) # "numeric"
n <- 5L ; class(n) # "integer"
s <- "Lucknow" ; class(s) # "character"
b <- 10 > 3 ; class(b) # "logical"
g <- factor(c("B", "A", "C", "A"), levels = c("C", "B", "A"), ordered = TRUE)
g > "B" # FALSE TRUE FALSE TRUE (A ranks above B)
table(g) # C: 1 B: 1 A: 2
Worked example – interval versus ratio. Is 20 °C "twice as hot" as 10 °C? Celsius is an interval scale with an arbitrary zero, so no. Converting to kelvin, a ratio scale: 20 °C = 293.15 K and 10 °C = 283.15 K, so the true ratio is 293.15 / 283.15 = 1.035 — only 3.5% hotter. Differences are still valid on both scales: 20 − 10 = 10 °C = 10 K.
2.4 Descriptive statistics
Descriptive statistics summarise a dataset with a few numbers. Measures of central tendency describe the centre: the mean (average), the median (middle value when sorted, robust to outliers) and the mode (most frequent value). Measures of dispersion describe the spread: the range (maximum − minimum), the variance (average squared deviation from the mean, using n − 1 for a sample), the standard deviation (square root of the variance, in the original units), the quartiles Q1 and Q3 with the interquartile range IQR = Q3 − Q1, and the coefficient of variation CV = SD / mean, which compares spread across variables with different units. Shape is described by skewness (asymmetry) and kurtosis (heaviness of the tails). In R these are given by mean(), median(), var(), sd(), range(), quantile(), IQR() and summary().
Worked example. Data: 4, 8, 6, 5, 3, 7, 9, 6 (n = 8).
- Mean = (4 + 8 + 6 + 5 + 3 + 7 + 9 + 6) / 8 = 48 / 8 = 6.
- Median: sorted 3, 4, 5, 6, 6, 7, 8, 9; the middle two values are 6 and 6, so median = 6.
- Mode = 6 (appears twice). Range = 9 − 3 = 6.
- Variance: deviations from 6 are −2, 2, 0, −1, −3, 1, 3, 0; their squares 4, 4, 0, 1, 9, 1, 9, 0 sum to 28; variance = 28 / (8 − 1) = 4; SD = √4 = 2.
- Quartiles (R's default method, position = 1 + p(n − 1)): Q1 is at position 2.75 → 4 + 0.75 × (5 − 4) = 4.75; Q3 is at position 6.25 → 7 + 0.25 × (8 − 7) = 7.25; IQR = 2.5.
- CV = 2 / 6 = 33.3%. Since mean = median, the data is roughly symmetric (skewness ≈ 0).
x <- c(4, 8, 6, 5, 3, 7, 9, 6)
mean(x); median(x); var(x); sd(x) # 6 6 4 2
quantile(x) # 0%: 3 25%: 4.75 50%: 6 75%: 7.25 100%: 9
IQR(x); sd(x) / mean(x) # 2.5 0.333
2.5 Exploratory data analysis
Exploratory data analysis (EDA), a term popularised by the statistician John Tukey, is the stage in which the analyst investigates a dataset with summaries and graphs before any formal modelling. Its aims are to understand the structure of the data, check data quality, discover patterns and relationships, detect outliers and anomalies, test assumptions such as normality, and generate hypotheses for modelling. A typical EDA in R proceeds in steps: inspect the structure (dim(), str(), head()); compute summaries (summary()); check missing values (colSums(is.na(df))); study each variable's distribution with histograms, density plots and box plots (univariate analysis); study relationships between pairs with scatter plots, correlation matrices and cross-tabulations (bivariate analysis) and with pair plots or grouped charts (multivariate analysis); and identify outliers with box plots or the IQR rule.
Worked example – EDA on the built-in mtcars data (32 cars, 11 variables).
dim(mtcars)returns 32 rows, 11 columns, andcolSums(is.na(mtcars))shows no missing values.summary(mtcars$mpg)gives minimum 10.4, median 19.2, mean 20.09 and maximum 33.9 miles per gallon. The mean is above the median, so mpg is slightly right-skewed.cor(mtcars$mpg, mtcars$wt)returns −0.87: heavier cars travel much less distance per gallon — a strong negative relationship and an obvious hypothesis for a regression model.boxplot(mpg ~ cyl, data = mtcars)shows median mpg falling from 26 (4 cylinders) to 19.7 (6 cylinders) to 15.2 (8 cylinders).
str(mtcars); summary(mtcars)
hist(mtcars$mpg, main = "Distribution of mpg", col = "lightblue")
boxplot(mpg ~ cyl, data = mtcars, main = "mpg by cylinders")
round(cor(mtcars[, c("mpg", "hp", "wt")]), 2)
pairs(mtcars[, c("mpg", "hp", "wt")])
2.6 Visualization before analysis
Data should always be plotted before it is analysed, because summary statistics can hide very different patterns. A correlation coefficient or a regression line describes the data correctly only if the relationship really is linear and free of outliers, and only a picture reveals whether this is true. Plotting first exposes non-linear relationships, outliers, clusters, gaps, data-entry errors and skewed distributions, and it guides the choice of model. The classic demonstration is Anscombe's quartet, four small datasets published by the statistician Francis Anscombe in 1973 and built into R as the dataset anscombe.
Worked example – Anscombe's quartet. Each of the four datasets has 11 (x, y) pairs, and all four share almost the same summary statistics:
| Statistic | Value in all four datasets |
|---|---|
| Mean of x | 9 |
| Variance of x | 11 |
| Mean of y | 7.50 |
| Variance of y | 4.12 (±0.003) |
| Correlation of x and y | 0.816 |
| Regression line | y = 3.00 + 0.500x |
Yet their plots are completely different. Dataset I is a genuine noisy linear relationship. Dataset II is a smooth curve, so a straight line is the wrong model. Dataset III is a perfect line spoiled by one outlier, which drags the fitted slope. Dataset IV has every point at x = 8 except one extreme point at x = 19, which alone creates the apparent correlation. Analysing only the numbers would treat all four as identical.
sapply(1:4, function(i) cor(anscombe[[paste0("x", i)]], anscombe[[paste0("y", i)]])) # 0.816 four times
op <- par(mfrow = c(2, 2))
for (i in 1:4) {
x <- anscombe[[paste0("x", i)]]; y <- anscombe[[paste0("y", i)]]
plot(x, y, pch = 19, main = paste("Dataset", i), xlim = c(3, 20), ylim = c(2, 14))
abline(lm(y ~ x), col = "red")
}
par(op)
2.7 Analytics for unstructured data
Unstructured data — text, images, audio and video — makes up most of the data organisations hold, but it has no rows and columns, so it must first be converted into a structured form. For text, the usual pipeline is: collect the documents; clean them (lower-case, remove punctuation, numbers and stop words); split them into words (tokenisation); reduce words to their roots (stemming or lemmatisation); build a document–term matrix (DTM) whose rows are documents and columns are terms; weight the terms, commonly with TF-IDF; and then analyse — word frequencies and word clouds, sentiment analysis, topic modelling (such as LDA), document clustering and classification. TF-IDF rewards words that are frequent in a document but rare across the collection: tf-idf(t, d) = tf(t, d) × log(N / df(t)), where tf is the term's frequency in document d, N is the number of documents and df(t) is the number of documents containing t. Images are analysed by extracting features or with deep convolutional networks; audio is converted to text (speech-to-text) or to frequency features; and video is treated as a sequence of images. In R, text analytics uses the tm, tidytext, quanteda, SnowballC, wordcloud and topicmodels packages.
Worked example – TF-IDF. A collection has N = 3 documents of 100 words each. "data" appears 3 times in document 1 and also appears in document 2 (df = 2). "hadoop" appears 2 times in document 1 and in no other document (df = 1). Using log base 10:
- tf(data, d1) = 3 / 100 = 0.03; idf(data) = log₁₀(3 / 2) = 0.176; tf-idf = 0.03 × 0.176 = 0.0053.
- tf(hadoop, d1) = 2 / 100 = 0.02; idf(hadoop) = log₁₀(3 / 1) = 0.477; tf-idf = 0.02 × 0.477 = 0.0095.
- Although "data" occurs more often in document 1, "hadoop" gets almost twice the weight because it is distinctive to that document. A word that appears in all three documents gets idf = log₁₀(3 / 3) = 0 and is ignored.
Lab 14 in Chapter 14 applies this pipeline in R to build a word cloud.
2.8 R fundamentals labs
These three labs build the R basics used in every later lab. Run them in RStudio; readline() asks for input only in an interactive session (in a script run with Rscript, use readLines("stdin", n = 1) instead).
Lab 1 (R) – User input and numerical operations (MAX, MIN, AVG, SUM, SQRT, ROUND)
# Read numbers from the user, e.g. 12, 7.5, 3, 20
input <- readline(prompt = "Enter numbers separated by commas: ")
nums <- as.numeric(trimws(strsplit(input, ",")[[1]]))
cat("Numbers entered :", nums, "\n")
cat("Maximum :", max(nums), "\n")
cat("Minimum :", min(nums), "\n")
cat("Sum :", sum(nums), "\n")
cat("Average :", mean(nums), "\n")
cat("Square roots :", round(sqrt(nums), 3), "\n")
cat("Average rounded :", round(mean(nums), 2), "\n")
# Single number example
x <- as.numeric(readline("Enter one number: "))
cat("sqrt =", sqrt(x), " round(sqrt, 2) =", round(sqrt(x), 2), "\n")
Note: sqrt() of a negative number returns NaN with a warning; check with if (x < 0) first.
Lab 2 (R) – Data import/export (.CSV, .XLS/.XLSX, .TXT) using data frames
install.packages(c("readxl", "writexl"))
library(readxl); library(writexl)
# Create a data frame
students <- data.frame(
roll = 1:5,
name = c("Asha", "Ravi", "Neha", "Aman", "Priya"),
marks = c(78, 85, 62, 90, 71)
)
# ---- Export ----
write.csv(students, "students.csv", row.names = FALSE) # CSV
write.table(students, "students.txt", sep = "\t", row.names = FALSE) # TXT (tab-separated)
write_xlsx(students, "students.xlsx") # Excel
# ---- Import ----
csv_df <- read.csv("students.csv")
txt_df <- read.table("students.txt", header = TRUE, sep = "\t")
xlsx_df <- read_excel("students.xlsx", sheet = 1) # also reads old .xls files
# ---- Inspect the imported data frames ----
str(csv_df); head(txt_df); summary(xlsx_df)
# Interactive file choice
# df <- read.csv(file.choose())
Lab 3 (R) – Matrix input and operations (addition, subtraction, multiplication, inverse, transpose, division)
read_matrix <- function(name) {
r <- as.integer(readline(paste("Rows of", name, ": ")))
c <- as.integer(readline(paste("Columns of", name, ": ")))
v <- as.numeric(strsplit(readline(paste("Enter", r * c,
"elements of", name, "row-wise, separated by spaces: ")), " +")[[1]])
matrix(v, nrow = r, ncol = c, byrow = TRUE) # vector -> matrix
}
A <- read_matrix("A") # e.g. 2 x 2: 4 7 2 6
B <- read_matrix("B") # e.g. 2 x 2: 1 2 3 4
print(A); print(B)
cat("\nAddition A + B\n"); print(A + B)
cat("\nSubtraction A - B\n"); print(A - B)
cat("\nElement-wise product A * B\n"); print(A * B)
cat("\nMatrix product A %*% B\n"); print(A %*% B) # needs ncol(A) == nrow(B)
cat("\nTranspose of A\n"); print(t(A))
cat("\nElement-wise division A / B\n"); print(A / B)
if (nrow(A) == ncol(A) && det(A) != 0) {
cat("\nInverse of A\n"); print(solve(A))
cat("\nCheck A %*% inverse(A)\n"); print(round(A %*% solve(A), 10))
} else cat("\nA is not square or is singular - no inverse\n")
if (nrow(B) == ncol(B) && det(B) != 0) {
cat("\nMatrix division A x inverse(B)\n"); print(A %*% solve(B))
}
Addition, subtraction and element-wise operations need A and B of the same size; matrix division is defined as A × B⁻¹.
Independent study notes written in my own words, for learning purposes. Not affiliated with any university or course provider. R, RStudio, Hadoop, Amazon S3, Tableau, Power BI and other product names are trademarks of their respective owners.