Author: Pooja Kotwani

  • Explicit Coercion in R Programming

    Explicit Coercion and Their Types

    Explicit coercion refers to the process of converting an object from one type of class to another using specific functions. These functions are similar to base functions but differ in that they are not generic and do not call S3 class methods for conversion.

    Difference Between Conversion, Coercion, and Casting
    • Coercion: Refers to implicit conversion of data types.
    • Casting: Refers to explicit conversion of data types.
    • Conversion: A general term that encompasses both coercion and casting.
    Explicit Coercion to Character

    To explicitly convert an object to a character type, two functions can be used: as.character() and as.string(). The encoding parameter informs the R compiler about the encoding of the vector and assists in managing character and string vectors.

    Example:

    # Creating a vector
    v <- c(10, 20, 30, 40)
    
    # Converting to character type
    as.character(v)

    Output:

    [1] "10" "20" "30" "40"
    Explicit Coercion to Numeric and Logical

    Explicit coercion to numeric, logical, or other data types is done using as.* functions, where the * represents the target data type. These functions take a vector as their parameter.

    Function Descriptions

    FunctionDescription
    as.logicalConverts values to logical type.0 is converted to FALSE.Non-zero values are converted to TRUE.
    as.integerConverts the object to integer type.
    as.doubleConverts the object to double precision type.
    as.complexConverts the object to complex type.
    as.listAccepts a vector or dictionary as input.

    Example:

    # Creating a vector
    x <- c(0, 1, 2, 3)
    
    # Checking the class of the vector
    class(x)
    
    # Converting to integer type
    as.integer(x)
    
    # Converting to double type
    as.double(x)
    
    # Converting to logical type
    as.logical(x)
    
    # Converting to a list
    eas.list(x)
    
    # Converting to complex type
    as.complex(x)

    Output:

    [1] "numeric"
    [1] 0 1 2 3
    [1] 0 1 2 3
    [1] FALSE  TRUE  TRUE  TRUE
    [[1]]
    [1] 0
    
    [[2]]
    [1] 1
    
    [[3]]
    [1] 2
    
    [[4]]
    [1] 3
    
    [1] 0+0i 1+0i 2+0i 3+0i
    Handling NAs During Coercion

    If R cannot determine how to coerce an object, it will produce NA values and issue a warning.

    Example:

    # Creating a vector with non-numeric values
    x <- c("apple", "banana", "cherry")
    
    # Attempting to convert to numeric
    as.numeric(x)
    
    # Attempting to convert to logical
    as.logical(x)

    Output:

    [1] NA NA NA
    Warning message:
    NAs introduced by coercion
    [1] NA NA NA
  • S3 class in R Programming

    S3 class and Their Types

    In R, everything is considered an object. Objects have attributes, and one of the most commonly associated attributes is the class. The class() command is used to define the class of an object or determine the class of an object.

    Key Features of Class in R:
    1. Inheritance: Objects can inherit from multiple classes.
    2. Order of Inheritance: For complex classes, the order of inheritance can be specified.

    Example: Checking the class of an object

    # Creating a vector of fruits
    fruits <- c("apple", "banana", "cherry")
    
    # Checking the class of the vector
    class(fruits)

    Output:

    [1] "character"

    Example: Appending a class to an object

    # Creating a vector of fruits
    fruits <- c("apple", "banana", "cherry")
    
    # Appending the class "Food" to the vector
    class(fruits) <- append(class(fruits), "Food")
    class(fruits)

    Output:

    [1] "character" "Food"
    Managing Memory in R

    When deciding between S3 and S4 classes in R, S4 offers a more structured approach, while S3 provides flexibility due to its less strict framework.

    Memory environments contribute to S3’s flexibility. An environment is similar to a local scope, maintaining a variable set associated with it. Variables within the environment can be accessed if the environment’s ID is known.

    To assign or retrieve variable values in an environment, assign() and get() commands are used.

    Example: Assigning and retrieving variable values in an environment

    $name
    [1] "John"
    
    $Roll_No
    [1] 101
    
    attr(,"class")
    [1] "Student"

    Output:

    <environment: R_GlobalEnv>
    [1] "colors" "env"
    [1] "yellow" "purple" "orange"
    Creating an S3 Class in R

    S3 is the simplest and most widely used class system in R. An S3 object is essentially a list with assigned class attributes.

    Steps to create an S3 object:

    1. Create a list containing the required components.
    2. Use class() to assign a class name to the list.

    Example 1: Creating an S3 object for employee details

    # Creating a list for employee details
    employee <- list(name = "Ravi", emp_id = 1001, salary = 50000)
    
    # Assigning the class "employee" to the list
    class(employee) <- "employee"
    employee

    Output:

    $name
    [1] "Ravi"
    
    $emp_id
    [1] 1001
    
    $salary
    [1] 50000
    
    attr(,"class")
    [1] "employee"

    Example 2: Creating an S3 object for book details

    # Creating a list for book details
    book <- list(title = "Data Science Basics", author = "John Doe", pages = 250)
    
    # Assigning the class "book" to the list
    class(book) <- "book"
    book

    Output:

    $title
    [1] "Data Science Basics"
    
    $author
    [1] "John Doe"
    
    $pages
    [1] 250
    
    attr(,"class")
    [1] "book"
    Generic Functions in R

    R uses generic functions, which are capable of operating differently on various classes of objects. A common generic function is print().

    For example, the print() function can print different types of objects like vectors, data frames, and matrices. This is possible because print() is a generic function comprising multiple methods.

    Example: Methods of the print() function

    # Checking methods available for the generic print() function
    methods(print)

    Output:

    [1] print.data.frame   print.default    print.matrix
  • R – Creating, Listing, and Deleting Objects in Memory

    Creating, Listing, and Deleting Objects in Memory with Example

    In R, what is often referred to as an “object” is equivalent to what many other programming languages call a “variable.” Objects and variables, depending on the context, can have very different interpretations. Variables in all programming languages provide a way to access data stored in memory. However, R does not offer direct access to memory; instead, it provides various specialized data structures, referred to as objects.

    In R, objects are accessed through symbols or variable names. Interestingly, symbols in R are themselves objects and can be manipulated like other objects. This unique feature of R has significant implications. In R, everything, from numbers to strings, arrays, vectors, lists, and data frames, is treated as an object.

    Creating Objects in Memory

    To perform operations in R, you must assign values to objects. This is done by giving the object a name, followed by an assignment operator (<- or =), and then the desired value.

    Example:

    # Assigning values to objects
    num <- 10
    text <- "Hello, R!"
    vec <- c(4, 8, 12)

    Here, the <- symbol is an assignment operator. For instance, after executing num <- 10, the value 10 is assigned to the object num. The assignment can be read as “10 is assigned to num.”

    variable_name <- list(attribute1, attribute2, ..., attributeN)
    Rules for Naming Objects
    1. Object names can be any combination of letters, numbers, and underscores, like ageuser_name, or id_number.
    2. Names cannot start with a number (e.g., 3var is invalid, but var3 is valid).
    3. R is case-sensitive (Data and data are different objects).
    4. Avoid using reserved keywords or function names (e.g., iffordata).
    5. Refrain from using dots in object names, as they have special meanings in R. Use underscores (_) instead.
    6. Prefer descriptive names for better readability. For example, use student_age instead of sa.
    7. Be consistent in naming conventions and coding styles.

    Creating Objects: Examples

    # Numeric object
    num <- 10
    print(num)
    
    # Character object
    message <- "Learning R is fun!"
    print(message)
    
    # Vector object
    num_vec <- c(2, 4, 6)
    print(num_vec)
    
    char_vec <- c("Red", "Green", "Blue")
    print(char_vec)
    
    # List object
    data_list <- list(
        "Numbers" = num_vec,
        "Colors" = char_vec
    )
    print(data_list)
    
    # Data frame object
    data_frame <- data.frame(
        "ID" = 1:3,
        "Name" = c("Alice", "Bob", "Carol")
    )
    print(data_frame)

    Output:

    [1] 10
    [1] "Learning R is fun!"
    [1] 2 4 6
    [1] "Red" "Green" "Blue"
    $Numbers
    [1] 2 4 6
    
    $Colors
    [1] "Red" "Green" "Blue"
    
      ID   Name
    1  1  Alice
    2  2    Bob
    3  3  Carol
    Listing Objects in Memory

    To list all objects in the current workspace, use the ls() or objects() function. Both return the names of all objects in memory as character vectors.

    Example:

    # Create objects
    num <- 10
    message <- "Hello"
    vec <- c(1, 2, 3)
    
    # List objects
    print(ls())
    print(objects())

    Output:

    [1] "message" "num" "vec"
    [1] "message" "num" "vec"

    Listing Objects Matching a Pattern

    You can also use ls() with a pattern to filter objects by name.

    # Create objects
    val1 <- 5
    value2 <- 10
    test_var <- "Sample"
    
    # List objects containing 'val'
    print(ls(pattern = "val"))
    
    # List objects ending with 'e'
    print(ls(pattern = "e$"))

    Output:

    [1] "val1" "value2"
    [1] "test_var"
    Deleting Objects in Memory

    To remove objects from the workspace, use the rm() or remove() function. Deleting objects helps free up memory and declutter the environment.

    Example:

    # Create objects
    x <- 25
    name <- "Sample Name"
    vec <- c(1, 2, 3)
    
    # Delete a specific object
    rm(x)
    
    # Delete another object
    remove(name)
    
    # List remaining objects
    print(ls())

    Output:

    [1] "vec"

    Deleting All Objects

    To delete all objects in memory, use rm(list = ls()).

    # Create objects
    a <- 15
    b <- "Hello"
    
    # Remove all objects
    rm(list = ls())
    
    # List objects
    print(ls())

    Output:

    character(0)

  • Looping over Objects in R Programming

    Looping over Objects and Their Types

    The “for” loop, while a fundamental construct in programming, is often criticized for its high memory consumption and slow execution, especially when dealing with large datasets. In R, alternative functions offer efficient ways to perform looping operations, particularly when working interactively in a command-line environment. Let’s explore these alternatives:

    Classes and Objects

    class is a template or blueprint from which objects are created by encapsulating data and methods. An object is a data structure containing attributes and methods that act upon those attributes.

    Overview of Looping Functions in R

    Looping FunctionOperation
    apply()Applies a function over the margins of an array or matrix
    lapply()Applies a function over a list or a vector
    sapply()Similar to lapply(), but returns simplified results
    tapply()Applies a function over subsets of a vector grouped by a factor
    mapply()Multivariate version of lapply()

    Let’s explore these functions with examples and their respective outputs.

    1. apply(): The apply() function applies a given function across the rows or columns of an array or matrix.

    Syntax:

    apply(array, margins, function, ...)
    • array: Input array or matrix
    • margins: Dimension along which to apply the function (1 for rows, 2 for columns)
    • function: Operation to perform

    Example:

    # Creating a matrix
    matrix_data <- matrix(1:12, nrow = 4, ncol = 3)
    print(matrix_data)
    
    # Applying apply() over rows
    row_sums <- apply(matrix_data, 1, sum)
    print(row_sums)
    
    # Applying apply() over columns
    col_sums <- apply(matrix_data, 2, sum)
    print(col_sums)

    Output:

    [,1] [,2] [,3]
    [1,]    1    5    9
    [2,]    2    6   10
    [3,]    3    7   11
    [4,]    4    8   12
    
    [1] 15 18 21 24
    [1] 10 26 42

    2. lapply():The lapply() function applies a function to each element of a list or vector and returns the results as a list.

    Syntax:

    lapply(list, function, ...)
    • list: Input list or vector
    • function: Operation to perform

    Example:

    # Creating a list of vectors
    list_data <- list(vec1 = c(1, 2, 3), vec2 = c(4, 5, 6))
    
    # Applying lapply()
    result <- lapply(list_data, mean)
    print(result)

    Output:

    $vec1
    [1] 2
    
    $vec2
    [1] 5

    3. sapply(): The sapply() function simplifies the output of lapply() when possible. It returns a vector, matrix, or list, depending on the input and output.

    Syntax:

    sapply(list, function, ...)
    • list: Input list or vector
    • function: Operation to perform

    Example:

    # Creating a list of vectors
    list_data <- list(vec1 = c(1, 2, 3), vec2 = c(4, 5, 6))
    
    # Applying lapply()
    result <- lapply(list_data, mean)
    print(result)

    Output:

    a b
    2 5

    4. tapply()The tapply() function applies a function over subsets of a vector grouped by a factor.

    Syntax:

    tapply(vector, factor, function, ...)
    tapply(vector, factor, function, ...)
    • vector: Input vector
    • factor: Grouping factor
    • function: Operation to perform

    Example:

    # Creating a numeric vector
    values <- c(10, 20, 30, 40, 50)
    
    # Creating a factor for grouping
    groups <- c("A", "A", "B", "B", "C")
    
    # Applying tapply()
    result <- tapply(values, groups, sum)
    print(result)

    Output:

    A   B   C
    30  70  50

    5. mapply():The mapply() function applies a function to multiple arguments simultaneously. It is a multivariate version of lapply().

    Syntax:

    mapply(function, list1, list2, ...)
    • function: Operation to perform
    • list1, list2: Input lists

    Example:

    # Creating two lists
    list1 <- list(c(1, 2, 3))
    list2 <- list(c(4, 5, 6))
    
    # Applying mapply()
    result <- mapply(sum, list1, list2)
    print(result)

    Output:

    [1] 5 7 9
    Looping Through a List

    Here are some additional ways to loop through lists and display elements:

    Display All Elements on the Same Line

    my_list <- c(1, 2, 3, 4, 5)
    
    for (element in my_list) {
      cat(element, " ")
    }

    Output:

    1 2 3 4 5

    Display All Elements on Different Lines

    for (element in my_list) {
      cat(element, "\n")
    }

    Output:

    1
    2
    3
    4
    5

    Display Specific Values

    for (element in my_list) {
      if (element %% 2 == 0) {  # Display only even values
        cat(element, "\n")
      }
    }

    Output:

    2
    4

    These functions provide flexible and efficient ways to handle looping operations in R, reducing memory consumption and improving execution speed. Use them in place of traditional “for” loops for better performance and cleaner code.

  • Abstraction in R Programming

    Abstraction and Their Types

    People who have been using the R programming language for a while are likely familiar with passing functions as arguments to other functions. However, they are less likely to return functions from their custom code. This is unfortunate, as doing so can unlock a new level of abstraction, reducing both the amount and complexity of the code required for certain tasks. Below, we present examples demonstrating how R programmers can leverage lexical closures to encapsulate both data and behavior.

    Implementation in R

    Simple Example: Adding Numbers

    To start with a simple example, suppose you want a function that adds 3 to its argument. You might write something like this:

    add_3 <- function(y) { 3 + y }

    This function works as expected:

    > add_3(1:10)
    [1]  4  5  6  7  8  9 10 11 12 13

    Now, suppose you need another function that adds 8 to its argument. Instead of writing a new function similar to add_3, a better approach is to create a function that generates these functions dynamically. Here’s how you can do that:

    add_x <- function(x) {
      function(y) { x + y }
    }

    Calling add_x with an argument returns a new function that performs the desired operation:

    add_3 <- add_x(3)
    add_8 <- add_x(8)
    
    > add_3(1:10)
    [1]  4  5  6  7  8  9 10 11 12 13
    > add_8(1:10)
    [1]  9 10 11 12 13 14 15 16 17 18

    If you closely examine the definition of add_x, you may wonder how the returned function knows about x when it is called later. This behavior is due to R’s lexical scoping. When add_x is called, the x argument is captured in the environment of the returned function.

    Advanced Example: Bootstrapping with Containers

    Now, let’s look at a more practical example. Suppose you’re performing some complex bootstrapping, and for efficiency, you pre-allocate vectors to store results. Here’s a straightforward implementation for a single vector:

    nboot <- 100
    bootmeans <- numeric(nboot)
    data <- rnorm(1000)  # Example dataset
    
    for (i in 1:nboot) {
      bootmeans[i] <- mean(sample(data, length(data), replace = TRUE))
    }
    
    > mean(data)
    [1] -0.0024
    > mean(bootmeans)
    [1] -0.0018

    However, if you need to track multiple statistics, each requiring a unique index variable, this process can become tedious and error-prone. Using closures, you can abstract away the bookkeeping. Here’s a function that creates a pre-allocated container:

    make_container <- function(n) {
      x <- numeric(n)
      i <- 1
    
      function(value = NULL) {
        if (is.null(value)) {
          return(x)
        } else {
          x[i] <<- value
          i <<- i + 1
        }
      }
    }

    Calling make_container with a size n returns a function that manages the container. If the argument to the function is NULL, it returns the entire vector. Otherwise, it adds the value to the next position in the vector:

    nboot <- 100
    bootmeans <- make_container(nboot)
    data <- rnorm(1000)
    
    for (i in 1:nboot) {
      bootmeans(mean(sample(data, length(data), replace = TRUE)))
    }
    
    > mean(data)
    [1] -0.0024
    > mean(bootmeans())
    [1] -0.0019

    This approach simplifies the management of multiple containers and ensures that indexing is handled internally.

  • R – Inheritance

    Inheritance and Their Types

    Inheritance is one of the key concepts in object-oriented programming, enabling new classes to be derived from existing or base classes, thereby enhancing code reusability. Derived classes can inherit properties and behaviors from the base class or include additional features, creating a hierarchical structure in the programming environment. This article explores how inheritance is implemented in R programming using three types of classes: S3, S4, and Reference Classes.

    Inheritance in S3 Class

    S3 classes in R are informal and have no rigid definitions. They use lists with a class attribute set to a class name. Objects of S3 classes inherit only methods from their base class.

    Example:

    # Create a function to define a class
    employee <- function(n, a, e){
      obj <- list(name = n, age = a, emp_id = e)
      attr(obj, "class") <- "employee"
      obj
    }
    
    # Define a method for the generic function print()
    print.employee <- function(obj){
      cat("Name:", obj$name, "\n")
      cat("Age:", obj$age, "\n")
      cat("Employee ID:", obj$emp_id, "\n")
    }
    
    # Create an object and inherit the class
    e <- list(name = "Priya", age = 30, emp_id = 123,
              department = "HR")
    class(e) <- c("Manager", "employee")
    
    cat("Using the inherited method print.employee():\n")
    print(e)
    
    # Overwrite the print method
    print.Manager <- function(obj){
      cat(obj$name, "is a Manager in", obj$department, "department.\n")
    }
    
    cat("After overwriting the method print.employee():\n")
    print(e)
    
    # Check inheritance
    cat("Is the object 'e' inherited from class 'employee'?\n")
    inherits(e, "employee")

    Output:

    Using the inherited method print.employee():
    Name: Priya
    Age: 30
    Employee ID: 123
    After overwriting the method print.employee():
    Priya is a Manager in HR department.
    Is the object 'e' inherited from class 'employee'?
    [1] TRUE
    Inheritance in S4 Class

    S4 classes in R are more formal, with strict definitions for slots. Derived classes can inherit both attributes and methods from the base class.

    Example:

    # Define an S4 class
    setClass("employee",
             slots = list(name = "character",
                          age = "numeric", emp_id = "numeric")
    )
    
    # Define a method to display object details
    setMethod("show", "employee",
              function(obj){
                cat("Name:", obj@name, "\n")
                cat("Age:", obj@age, "\n")
                cat("Employee ID:", obj@emp_id, "\n")
              }
    )
    
    # Create a derived class
    setClass("Manager",
             slots = list(department = "character"),
             contains = "employee"
    )
    
    # Create an object of the derived class
    m <- new("Manager", name = "Priya", age = 30, emp_id = 123, department = "HR")
    show(m)

    Output:

    Name: Priya
    Age: 30
    Employee ID: 123
    Inheritance in Reference Class

    Reference classes use the setRefClass() function to create classes and manage inheritance. The concept is similar to S4 classes but supports mutable objects.

    Example:

    # Define a reference class
    employee <- setRefClass("employee",
                            fields = list(name = "character",
                                          age = "numeric", emp_id = "numeric"),
                            methods = list(
                              increment_age = function(x) {
                                age <<- age + x
                              },
                              decrement_age = function(x) {
                                age <<- age - x
                              }
                            )
    )
    
    # Create a derived reference class
    Manager <- setRefClass("Manager",
                           fields = list(department = "character"),
                           contains = "employee",
                           methods = list(
                             decrement_age = function(x) {
                               if ((age - x) < 0) stop("Age cannot be negative")
                               age <<- age - x
                             }
                           )
    )
    
    # Create an object
    mgr <- Manager(name = "Priya", age = 30, emp_id = 123, department = "HR")
    
    cat("Decreasing age by 5:\n")
    mgr$decrement_age(5)
    mgr$age
    
    cat("Attempting to decrease age by 30:\n")
    mgr$decrement_age(30)
    mgr$age

    Output:

    Decreasing age by 5:
    [1] 25
    Attempting to decrease age by 30:
    Error in mgr$decrement_age(30) : Age cannot be negative
    [1] 25
  • Polymorphism in R Programming

    Polymorphism

    R supports parametric polymorphism, enabling methods (functions) to operate on a variety of object types. Unlike class-based systems, R’s methods are tied to functions rather than classes. This mechanism allows the creation of generic methods or functions that can handle diverse object types, even ones not explicitly defined. By utilizing this, developers can use the same function name across different object classes, with behavior tailored for each.

    Generic Functions in R

    Polymorphism in R is achieved through generic functions, which serve as dispatchers. These functions invoke specific methods based on the class of their input objects. For instance, R’s plot() and summary() functions adapt their behavior depending on the type of object they receive as input.

    Example: plot() Function

    The plot() function demonstrates polymorphism by producing different visualizations depending on the type of input—numeric vectors, factors, or data frames.

    Structure of plot() Function

    plot

    Example:

    function (x, y, ...)
    UseMethod("plot")

    The UseMethod("plot") directive ensures the appropriate plot method is called based on the input object’s class.

    Example:

    methods(plot)

    Output:

    Viewing Available Methods for plot()

    Available Methods
    plot.default
    plot.function
    plot.lm
    plot.ts
    plot.factor
    plot.data.frame
    plot.histogram
    plot.ecdf
    plot.stepfun
    plot.hclust
    plot.prcomp
    plot.density
    plot.qqnorm

    Single Numeric Vector: When a numeric vector is passed to plot(), it produces a line graph.

    # Example: Single Numeric Vector
    x <- 1:20
    plot(x, type = 'l', col = 'blue')

    Output:

    Two Numeric Vectors: Passing two numeric vectors generates a scatter plot.

    # Example: Two Numeric Vectors
    x <- 1:10
    y <- x * 2
    plot(x, y, type = 'p', col = 'red', pch = 16)

    Output:

    Factor: Passing a factor to plot() produces a bar chart.

    # Example: Factor
    categories <- factor(c('A', 'B', 'A', 'C', 'B', 'C', 'A'))
    plot(categories, col = 'green')

    Output:

    Data Frame: When a data frame is passed, plot() generates pairwise scatter plots for its numeric columns.

    # Example: Data Frame
    df <- data.frame(a = rnorm(10), b = runif(10), c = rnorm(10))
    plot(df, col = 'purple', pch = 19)

    Output:

    Example: summary() Function

    The summary() function provides summaries tailored to the input object, showcasing its polymorphic nature.

    Character Vector

    colors <- c("red", "blue", "green", "yellow")
    summary(colors)

    Output:

    Length     Class      Mode
    4      character character

    Factor

    regions <- factor(c("North", "South", "East", "North", "West"))
    summary(regions)

    Output:

    East North South West
    1     2     1     1

    Numeric Data

    data <- rnorm(10)
    summary(data)

    Output:

    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.
    -1.900  -0.610   0.300   0.010   0.850   1.650
    Creating Custom Generic Methods

    Here’s how you can create your own generic methods in R:

    Step 1: Define the Generic Function

    display <- function(obj) {
        UseMethod("display")
    }

    Step 2: Define the Method for a Specific Class

    display.bank <- function(obj) {
        cat("Account Holder:", obj$name, "\n")
        cat("Account Number:", obj$account_no, "\n")
        cat("Balance:", obj$balance, "\n")
        cat("Withdrawals:", obj$withdrawn, "\n")
    }

    Step 3: Create an Object and Assign a Class

    account <- list(name = "John Doe", account_no = 12345, balance = 5000, withdrawn = 1200)
    class(account) <- "bank"

    Step 4: Call the Generic Function

    display(account)

    Output:

    Account Holder: John Doe
    Account Number: 12345
    Balance: 5000
    Withdrawals: 1200
  • Encapsulation in R Programming

    Encapsulation

    While working with classes and dealing with sensitive data, implementing global access to all the variables used within the program code is not a good choice because then the chances of data being tampered with will increase. For this purpose, Object-Oriented Programming languages have the concept of Encapsulation.

    Encapsulation ensures that the outside view of the object is clearly separated from the inside view of the object by hiding the implementation of operations and state from the interface, which is available to all other objects.

    What is Encapsulation?

    Encapsulation is:

    • Binding the data with the code that manipulates it.
    • Keeping the data and the code safe from external interference.

    A common analogy to understand encapsulation is when you visit a restaurant. The waiter comes to take your order and delegates the preparation to the chef. You, as a customer, do not directly interact with the chef. Similarly, in programming, encapsulation ensures that objects communicate with one another via well-defined methods, rather than allowing direct access to internal details.

    This helps in:

    1. Improved control over input data.
    2. Enhanced security.
    3. Reduced vulnerability of data tampering.
    4. Building loosely coupled code.

    Examples of Encapsulation in R Programming

    Example 1

    # Creating a list
    car <- list(model_name = "Sedan",
                engine = "Diesel",
                max_speed = 180)
    
    # Assigning a class to the list
    class(car) <- "Vehicle"
    
    # Printing the object of class 'Vehicle'
    car

    Output:

    $model_name
    [1] "Sedan"
    
    $engine
    [1] "Diesel"
    
    $max_speed
    [1] 180
    
    attr(,"class")
    [1] "Vehicle"

    Example:

    # Creating a list
    location <- list(city = "Mumbai",
                     state = "Maharashtra",
                     pincode = 400001)
    
    # Assigning a class to the list
    class(location) <- "Address"
    
    # Printing the object of class 'Address'
    location

    Output:

    $city
    [1] "Mumbai"
    
    $state
    [1] "Maharashtra"
    
    $pincode
    [1] 400001
    
    attr(,"class")
    [1] "Address"

    Key Takeaways

    When using encapsulated code like the above examples, keep the following points in mind:

    1. Ease of Access: Everyone knows how to access the encapsulated object.
    2. Abstraction: Can be easily used regardless of the implementation details.
    3. No Side Effects: Encapsulation ensures there are no unintended effects on the rest of the application.

    Encapsulation also aids in creating more maintainable code, blocking the ripple effects of code changes, and helping to build loosely coupled systems by minimizing direct access to an object’s internal state and behavior.

  • Objects in R Programming

    Introduction to Objects in R

    In R, everything is an object. This is one of the most important concepts to understand when learning R programming. Variables, data structures, functions, models, and even expressions are treated as objects stored in memory.

    An object in R is a named container that holds data, attributes, and sometimes behavior.

    Examples of objects:

    • Numeric values
    • Vectors
    • Matrices
    • Data frames
    • Lists
    • Functions
    • Models (like linear regression results)

    What is an Object?

    An object is a data entity stored in memory that has:

    1. A value (data)
    2. A type (numeric, character, list, etc.)
    3. Attributes (optional metadata)
    4. A class (used in OOP)

    Example:

    x <- 10
    

    Here:

    • x is an object
    • 10 is the value
    • Type is numeric
    • Class is numeric

    Everything in R is an Object

    In R:

    • Numbers are objects
    • Strings are objects
    • Functions are objects
    • Data frames are objects

    Example:

    x <- 5
    y <- "R"
    f <- function(a) a + 1
    

    Check their classes:

    class(x)
    class(y)
    class(f)
    

    Creating Objects in R

    Objects are created using the assignment operator <- (preferred) or =.

    a <- 100
    b = "Data Science"
    

    Each assignment creates an object in memory.


    Naming Objects

    Object names follow the same rules as variable names.

    Rules:

    • Must start with a letter or .
    • Cannot start with a number
    • Case-sensitive
    • Cannot be reserved keywords

    Valid:

    score <- 95
    .myObject <- 10
    

    Invalid:

    1score <- 95
    

    Types of Objects in R

    Objects in R can be categorized based on the data they store.

    Atomic Objects

    These store a single type of data.

    • Numeric
    • Integer
    • Character
    • Logical
    • Complex

    Example:

    x <- 10
    y <- TRUE
    z <- "R"
    

    Composite Objects

    These store multiple values and structures.

    Object TypeDescription
    Vector1D, same data type
    Matrix2D vector
    ArrayMulti-dimensional
    ListDifferent data types
    Data FrameTabular data

    Example:

    v <- c(1, 2, 3)
    m <- matrix(1:6, nrow = 2)
    l <- list(1, "R", TRUE)
    df <- data.frame(id=1:3, name=c("A","B","C"))
    

    Object Attributes

    Attributes provide additional information about an object.

    Common attributes:

    • names
    • dim
    • class
    • levels

    Example:

    v <- c(a=10, b=20)
    attributes(v)
    

    Accessing Attributes

    Using attributes()

    attributes(v)
    

    Using attr()

    attr(v, "names")
    

    Modifying Attributes

    attr(v, "comment") <- "Score values"
    

    Class of an Object

    The class determines how an object behaves in functions.

    class(v)
    

    Change class manually:

    class(v) <- "myVector"
    

    This is commonly used in S3 OOP.


    Object Structure – str()

    The str() function displays the internal structure of an object.

    str(df)
    

    Output shows:

    • Type
    • Length
    • Attributes
    • Data preview

    Checking Object Properties

    Type of Object

    typeof(x)
    

    Class of Object

    class(x)
    

    Length of Object

    length(v)
    

    Dimensions of Object

    dim(m)
    

    Copying Objects in R

    R uses copy-on-modify behavior.

    x <- c(1,2,3)
    y <- x
    y[1] <- 100
    

    x remains unchanged until modification.


    Reference Objects (R6)

    Some objects (like R6) use reference semantics.

    library(R6)
    
    Counter <- R6Class("Counter",
      public = list(
        value = 0,
        inc = function() self$value <- self$value + 1
      )
    )
    
    c1 <- Counter$new()
    c2 <- c1
    c2$inc()
    c1$value   # changed
    

    Listing Objects in Memory

    Use ls() to see objects in the current environment.

    ls()
    

    Removing Objects from Memory

    Use rm() to delete objects.

    rm(x)
    

    Remove multiple objects:

    rm(a, b, c)
    

    Remove all objects:

    rm(list = ls())
    

    Object Environments

    Objects live inside environments.

    Common environments:

    • Global Environment
    • Local Environment
    • Package Environment

    Check current environment:

    environment()
    

    Objects and Functions

    Functions are also objects.

    f <- function(x) x * 2
    class(f)
    

    Functions can be:

    • Passed as arguments
    • Returned from other functions
    • Stored in lists

    Looping Over Objects

    Example with vector:

    v <- c(10, 20, 30)
    for (i in v) {
      print(i)
    }
    

    Example with list:

    l <- list(1, "R", TRUE)
    for (item in l) {
      print(item)
    }
    

    Practical Example

    student <- list(
      name = "Alice",
      marks = c(80, 85, 90)
    )
    
    average <- mean(student$marks)
    average
    

    Common Mistakes with Objects

    • Confusing type and class
    • Modifying reference objects unintentionally
    • Forgetting objects are copied on modification
    • Removing important objects accidentally using rm()

    Summary

    • Everything in R is an object
    • Objects store data, attributes, and class
    • Objects live in environments
    • Understanding objects is essential for OOP, data analysis, and package development
    • Proper object management improves performance and code clarity
  • Classes in R Programming

    Classes in detail

    Classes and Objects form the foundation of Object-Oriented Programming (OOP). They revolve around real-world entities. In R, everything is treated as an object. An object is essentially a data structure that contains attributes and methods. A class acts as a template or blueprint for creating objects, defining a set of properties or behaviors common to all objects of that type.

    Unlike many other programming languages, R features a three-class system: S3S4, and Reference Classes.

    Classes and Objects

    class is a template or blueprint from which objects are created by encapsulating data and methods. An object is a data structure containing attributes and methods that act upon those attributes.

    S3 Class

    The S3 class is the simplest and most flexible OOP system in R. It does not enforce a rigid structure or formal definitions. You can create an object of the S3 class by assigning a class attribute to it.

    Example:

    # Create a list with relevant attributes
    bookDetails <- list(title = "The Alchemist", author = "Paulo Coelho")
    
    # Assign a class name
    class(bookDetails) <- "book"
    
    bookDetails

    Output:

    $title
    [1] "The Alchemist"
    
    $author
    [1] "Paulo Coelho"

    In S3, methods are not tied to specific classes but to generic functions. For example, you can customize how the print function behaves for your objects.

    Example: Custom Print Method

    # Define a custom print method for class "book"
    print.book <- function(obj) {
        cat("Title:", obj$title, "\n")
        cat("Author:", obj$author, "\n")
    }
    
    # Print the object
    print(bookDetails)

    Output:

    Title: The Alchemist
    Author: Paulo Coelho
    S4 Class

    The S4 class offers a more structured approach to OOP in R, which programmers familiar with C++ or Java may find more intuitive. It provides formal class definitions, which include specified slots for storing data.

    Example:

    library(methods)
    
    # Define an S4 class
    setClass("novel", slots = list(title = "character", author = "character"))
    
    # Create an object of the S4 class
    novelDetails <- new("novel", title = "1984", author = "George Orwell")
    novelDetails

    Output:

    An object of class "novel"
    Slot "title":
    [1] "1984"
    
    Slot "author":
    [1] "George Orwell"

    S4 classes also allow you to define methods. Here’s an example:

    Example: Custom Method

    # Define a custom method for class "novel"
    setMethod("show", "novel",
              function(object) {
                  cat("Title:", object@title, "\n")
                  cat("Author:", object@author, "\n")
              })
    
    # Display the object
    novelDetails

    Output:

    # View attributes
    attributes(student)

    You can also define methods for Reference Classes:

    Example: Adding Methods

    libraryDetails <- setRefClass("library", fields = list(
        name = "character",
        location = "character",
        booksAvailable = "numeric"
    ), methods = list(
        addBooks = function(count) {
            booksAvailable <<- booksAvailable + count
        },
        removeBooks = function(count) {
            booksAvailable <<- booksAvailable - count
        }
    ))
    
    # Create an object and manipulate its fields
    libraryInfo <- libraryDetails(name = "Central Library", location = "Downtown", booksAvailable = 5000)
    
    # Print books available
    libraryInfo$booksAvailable
    
    # Add 200 books and print the count
    libraryInfo$addBooks(200)
    libraryInfo$booksAvailable
    
    # Remove 100 books and print the count
    libraryInfo$removeBooks(100)
    libraryInfo$booksAvailable

    Output:

    [1] 5000
    [1] 5200
    [1] 5100