Combine Data Frames in R by Rows or Columns

In R, data frames can be combined in several ways. Use merge() when two data frames share a key column, rbind() when you want to append rows with matching columns, and cbind() when you want to place columns side by side.

The correct method depends on the structure of the data:

  • Use merge() to join data frames by one or more common columns.
  • Use rbind() to combine data frames vertically by adding rows.
  • Use cbind() to combine data frames horizontally by adding columns when their rows already correspond.

Combine R Data Frames by a Common Column with merge()

merge() combines rows from two data frames according to matching values in one or more key columns. By default, it returns rows whose key values occur in both data frames, which is similar to an inner join.

merge() function is used to merge data frames. The syntax of merge() function is:

</>
Copy
 merge(x, y, by, by.x, by.y, sort = TRUE)

where

  • x, y are data frames, or objects to be coerced or combined to one
  • by, by.x, by.y are specifcations of the common columns.
  • sort logical (TRUE or FALSE). Results are sorted on the by columns if TRUE and not if FALSE.

When the key column has the same name in both data frames, use by. When the key columns have different names, use by.x for the first data frame and by.y for the second.

Combine Student Data Frames by ID using merge()

In this example, we take two data frames. The first data frame contains id and name of students. The second data frame contains id and marks of students.

</>
Copy
> studentsDF = data.frame(id=c(1,2,3,4), name=c("John", "Manu", "Surya", "Amith"))
> marksDF = data.frame(id=c(1,2,3,4), marks=c(78, 88, 76, 91))
> studentsDF
  id  name
1  1  John
2  2  Manu
3  3 Surya
4  4 Amith
> marksDF
  id marks
1  1    78
2  2    88
3  3    76
4  4    91

You can combine these two data frames with respect to the common column id using merge() function.

</>
Copy
> studentMarksDF = merge(studentsDF, marksDF, by=c("id"))
> studentMarksDF
  id  name marks
1  1  John    78
2  2  Manu    88
3  3 Surya    76
4  4 Amith    91
>

The second data frame is added to the first data frame based on a column. The result is a new data frame with new columns.

This approach is useful when separate data sources describe the same records. For example, one table may contain student names while another contains marks, and both tables use id as the shared key.

Merge R Data Frames with Different Key Column Names

If the matching columns have different names, specify them with by.x and by.y.

</>
Copy
studentsDF <- data.frame(
  student_id = c(1, 2, 3),
  name = c("John", "Manu", "Surya")
)

marksDF <- data.frame(
  id = c(1, 2, 3),
  marks = c(78, 88, 76)
)

result <- merge(
  studentsDF,
  marksDF,
  by.x = "student_id",
  by.y = "id"
)

print(result)

Output

  student_id  name marks
1          1  John    78
2          2  Manu    88
3          3 Surya    76

Merge R Data Frames by Multiple Common Columns

To match rows using more than one column, pass a character vector to by. A row is matched only when all specified key values agree.

</>
Copy
studentsDF <- data.frame(
  id = c(1, 1, 2),
  term = c("A", "B", "A"),
  name = c("John", "John", "Manu")
)

marksDF <- data.frame(
  id = c(1, 1, 2),
  term = c("A", "B", "A"),
  marks = c(78, 82, 88)
)

result <- merge(
  studentsDF,
  marksDF,
  by = c("id", "term")
)

print(result)

Output

  id term name marks
1  1    A John    78
2  1    B John    82
3  2    A Manu    88

Control Inner, Left, Right, and Full Joins with merge()

The all, all.x, and all.y arguments control which unmatched rows are retained.

  • merge(x, y, by = "id") keeps matching rows only.
  • merge(x, y, by = "id", all.x = TRUE) keeps every row from x.
  • merge(x, y, by = "id", all.y = TRUE) keeps every row from y.
  • merge(x, y, by = "id", all = TRUE) keeps every row from both data frames.
</>
Copy
studentsDF <- data.frame(
  id = c(1, 2, 3),
  name = c("John", "Manu", "Surya")
)

marksDF <- data.frame(
  id = c(2, 3, 4),
  marks = c(88, 76, 91)
)

left_join_result <- merge(
  studentsDF,
  marksDF,
  by = "id",
  all.x = TRUE
)

print(left_join_result)

Output

  id  name marks
1  1  John    NA
2  2  Manu    88
3  3 Surya    76

The value NA indicates that no matching marks row was found for student ID 1.

Combine R Data Frames Vertically with rbind()

rbind() appends the rows of one data frame below another. The data frames should have compatible columns, usually with the same names and compatible data types.

rbind() function is used to concatenate data frames. The syntax of rbind() function is:

</>
Copy
 rbind(x, ...)

where

  • x an R6Frame
  • ... additional parameters sent to rbind

For data frames, x and the values supplied through ... are the objects whose rows will be combined.

Append Student Rows using rbind()

In this example, we take two data frames. The first data frame contains id and name of students. The second data frame also contains id and name of students. Consider that these are two batches of students and we would like to concatenate these.

</>
Copy
> studentsDF = data.frame(id=c(1,2,3,4), name=c("John", "Manu", "Surya", "Amith"))
> studentsDF
  id  name
1  1  John
2  2  Manu
3  3 Surya
4  4 Amith
> studentsSomeMoreDF = data.frame(id=c(5,6,7,8), name=c("Nivin", "Sruthy", "Kiku", "Mahesh"))
> studentsSomeMoreDF
  id   name
1  5  Nivin
2  6 Sruthy
3  7   Kiku
4  8 Mahesh
>

You can combine these two data frames with respect to rows using rbind() function.

</>
Copy
> allStudentsDF = rbind(studentsDF, studentsSomeMoreDF)
> allStudentsDF
  id   name
1  1   John
2  2   Manu
3  3  Surya
4  4  Amith
5  5  Nivin
6  6 Sruthy
7  7   Kiku
8  8 Mahesh
>

The rows of second data frame are added to that of first data frame. The result is a new data frame with increased number of rows.

Combine Multiple R Data Frames with the Same Columns

When several data frames have the same column structure, place them in a list and call do.call(rbind, ...).

</>
Copy
batch1 <- data.frame(
  id = c(1, 2),
  name = c("John", "Manu")
)

batch2 <- data.frame(
  id = c(3, 4),
  name = c("Surya", "Amith")
)

batch3 <- data.frame(
  id = c(5, 6),
  name = c("Nivin", "Sruthy")
)

allStudentsDF <- do.call(
  rbind,
  list(batch1, batch2, batch3)
)

print(allStudentsDF)

Output

  id   name
1  1   John
2  2   Manu
3  3  Surya
4  4  Amith
5  5  Nivin
6  6 Sruthy

Combine R Data Frames with Different Columns

Base R rbind() expects compatible column names. When two data frames contain different columns, add the missing columns before binding the rows, or use a row-binding function that can fill absent values with NA.

</>
Copy
studentsDF <- data.frame(
  id = c(1, 2),
  name = c("John", "Manu")
)

marksDF <- data.frame(
  id = c(3, 4),
  marks = c(76, 91)
)

all_columns <- union(
  names(studentsDF),
  names(marksDF)
)

add_missing_columns <- function(df, columns) {
  missing_columns <- setdiff(columns, names(df))
  df[missing_columns] <- NA
  df[columns]
}

studentsDF <- add_missing_columns(studentsDF, all_columns)
marksDF <- add_missing_columns(marksDF, all_columns)

combinedDF <- rbind(studentsDF, marksDF)
print(combinedDF)

Output

  id name marks
1  1 John    NA
2  2 Manu    NA
3  3 <NA>    76
4  4 <NA>    91

Combine R Data Frames Horizontally with cbind()

cbind() places columns side by side. Use it only when the rows in both data frames are already in the same order and represent the same observations.

</>
Copy
cbind(data_frame_1, data_frame_2)
</>
Copy
studentsDF <- data.frame(
  id = c(1, 2, 3),
  name = c("John", "Manu", "Surya")
)

marksDF <- data.frame(
  marks = c(78, 88, 76)
)

studentMarksDF <- cbind(studentsDF, marksDF)
print(studentMarksDF)

Output

  id  name marks
1  1  John    78
2  2  Manu    88
3  3 Surya    76

If the row order is uncertain, use merge() with a key column instead of cbind(). Otherwise, values may be attached to the wrong records.

Combine R Data Frames with dplyr Joins

The dplyr package provides named join functions that correspond to common data-joining operations.

  • inner_join() keeps matching rows from both data frames.
  • left_join() keeps every row from the first data frame.
  • right_join() keeps every row from the second data frame.
  • full_join() keeps every row from both data frames.
  • bind_rows() appends rows and can fill missing columns with NA.
</>
Copy
studentsDF <- data.frame(
  id = c(1, 2, 3),
  name = c("John", "Manu", "Surya")
)

marksDF <- data.frame(
  id = c(2, 3, 4),
  marks = c(88, 76, 91)
)

result <- dplyr::left_join(
  studentsDF,
  marksDF,
  by = "id"
)

print(result)

Output

  id  name marks
1  1  John    NA
2  2  Manu    88
3  3 Surya    76

Prevent Duplicate Rows When Merging R Data Frames

If a key value occurs more than once in either data frame, merge() returns every matching combination. This can increase the number of rows.

</>
Copy
x <- data.frame(
  id = c(1, 1),
  name = c("John A", "John B")
)

y <- data.frame(
  id = c(1, 1),
  marks = c(78, 82)
)

merge(x, y, by = "id")

Before joining, check whether the key is expected to be unique.

</>
Copy
anyDuplicated(studentsDF$id)
anyDuplicated(marksDF$id)

A result of 0 means no duplicate key value was found. A positive result identifies the position of the first duplicate.

Common Problems When Combining R Data Frames

  • Unexpected row multiplication: duplicate key values in one or both data frames can produce multiple matches.
  • Missing rows after merge: the default merge() keeps matching keys only. Use all.x, all.y, or all when unmatched rows must be retained.
  • Incorrect matches with cbind(): cbind() does not match rows by ID; it combines them by their current positions.
  • rbind() column mismatch: base R rbind() requires compatible columns. Align the column names before combining.
  • Different key data types: ensure matching columns use compatible types, such as both integer or both character.
  • Duplicate non-key column names: merge() may add suffixes such as .x and .y to distinguish them.

Frequently Asked Questions about Combining R Data Frames

How do I combine two R data frames by ID?

Use merge(df1, df2, by = "id") when both data frames contain an id column. Use by.x and by.y when the ID columns have different names.

How do I combine two data frames vertically in R?

Use rbind(df1, df2) when the data frames have matching columns. The rows from the second data frame are appended below the rows from the first.

How do I combine R data frames with different columns?

Add the missing columns to each data frame and fill them with NA before calling rbind(). Another option is dplyr::bind_rows(), which aligns columns by name and fills missing values automatically.

What is the difference between merge(), rbind(), and cbind() in R?

merge() matches rows by key values, rbind() appends rows vertically, and cbind() appends columns horizontally according to row position.

Why does merge() create more rows than the original data frames?

This usually happens when the key column contains duplicate values. Each matching occurrence in one data frame is paired with every matching occurrence in the other data frame.

Editorial QA Checklist for R Data Frame Combination Examples

  • Confirm that every merge() example identifies the correct key column or columns.
  • Check whether duplicate keys are intentional before accepting an increased row count.
  • Verify that examples using rbind() have compatible column names and data types.
  • Ensure that cbind() examples use data frames with corresponding rows in the same order.
  • Run each join example and verify that unmatched rows produce NA only where expected.
  • Check that inner, left, right, and full join descriptions match the arguments used in the code.

Summary of R Data Frame Combination Methods

Use merge() to combine data frames by shared key values, rbind() to append data frames with compatible columns, and cbind() to add columns when row order already matches. For joins with clearer names or for binding rows with different columns, functions such as dplyr::left_join() and dplyr::bind_rows() are useful alternatives.

In this R Tutorial, we have learned how to combine R Data Frames based on rows or columns.