HOWTO · R

How to Combine Two Data Frames in R

Choose between stacking rows with rbind() or dplyr::bind_rows(), and joining related records by keys with plyr::join() or merge().

On this page

To combine two data frames in R, first decide whether you are adding records or matching related records. Use rbind() when both inputs contain the same kind of records and compatible columns; use dplyr::bind_rows() when you want a row bind that can include columns found in only one input. Use plyr::join() or base merge() when rows should be matched by a key such as an ID. The examples below use small tables so you can adapt the column names and values to your data.

How to Combine Two Data Frames in R Using the rbind() Function

Base R’s rbind() appends the rows of one data frame after another. Give the inputs the same columns with matching names and compatible values. Matching names matter more than column order: rbind() aligns columns by name, so the values remain under their intended headings. It does not create a union of differently named columns or fill absent fields for you. If the inputs represent different fields, normalize their structure first or use bind_rows().

This example creates two tables of the same structure, then stacks their records with rbind():

x <- data.frame(
  id = c(1, 2),
  score = c(88, 91)
)
y <- data.frame(
  id = c(3, 4),
  score = c(85, 96)
)

combined <- rbind(x, y)
print(combined)
  id score
1  1    88
2  2    91
3  3    85
4  4    96

Each row in the result is another observation of the same variables. The first table’s rows stay first, followed by the rows from the second table. For data frames with a different set of fields, use bind_rows() so absent values can be represented as NA.

How to Combine Two Data Frames in R Using the dplyr Package

The dplyr package provides bind_rows() for stacking records when input data frames have different columns. It matches columns by name and includes columns present in either input; rows without a value for a column receive NA. This is useful when two sources describe the same kind of record but one source contains an additional field. It remains a row bind, so it does not match records by an ID.

Install dplyr with install.packages("dplyr") to use dplyr::bind_rows() in your own script. The example prefers that function when the package is installed; otherwise, its small base R fallback aligns the same named columns and fills absent values with NA, so the example can run without an additional package.

first <- data.frame(id = 1, score = 88)
second <- data.frame(id = 2, group = "B")

if (requireNamespace("dplyr", quietly = TRUE)) {
  combined <- dplyr::bind_rows(first, second)
} else {
  columns <- union(names(first), names(second))
  align_columns <- function(data) {
    for (column in setdiff(columns, names(data))) data[[column]] <- NA
    data[columns]
  }
  combined <- rbind(align_columns(first), align_columns(second))
}

cat("id score group\n")
for (i in seq_len(nrow(combined))) {
  score <- if (is.na(combined$score[i])) "NA" else as.character(combined$score[i])
  group <- if (is.na(combined$group[i])) "NA" else combined$group[i]
  cat(paste(combined$id[i], score, group), "\n", sep = "")
}
id score group
1 88 NA
2 NA B

How to Combine Two Data Frames in R Using the plyr Package

The plyr package’s join() combines related rows by key columns; it is a join, not a row bind. Set by to the shared key. With type = "inner", the result retains only keys present in both inputs; the default type = "left" keeps every row from the first input. Install plyr with install.packages("plyr") to use plyr::join() in your own script. The example prefers that function when available and otherwise uses base merge() for the same inner-join result. Consult ?plyr::join in the installed package when choosing another join type.

people <- data.frame(id = c(1, 2), name = c("Ada", "Ben"))
ages <- data.frame(id = c(2, 3), age = c(25, 30))

if (requireNamespace("plyr", quietly = TRUE)) {
  matched <- plyr::join(people, ages, by = "id", type = "inner")
} else {
  matched <- merge(people, ages, by = "id")
}

cat("id name age\n")
for (i in seq_len(nrow(matched))) {
  cat(paste(matched$id[i], matched$name[i], matched$age[i]), "\n", sep = "")
}
id name age
2 Ben 25

How to Combine Two Data Frames in R Using the merge() Function

Base R’s merge() joins data frames by matching values in key columns. When both inputs use a column with the same name, by identifies that key. By default, merge() keeps matching keys from both inputs, which is an inner join. Set all.x = TRUE to keep every row from x, all.y = TRUE to keep every row from y, or both to retain unmatched rows from both sides. Check that key columns have compatible types and that duplicate keys are intentional: repeated matches can produce multiple result rows.

This standalone example joins two tables on id and prints the matching records:

people <- data.frame(
  id = c(1, 2, 3),
  name = c("Ada", "Ben", "Cy")
)
ages <- data.frame(
  id = c(2, 3, 4),
  age = c(25, 30, 35)
)

matched <- merge(people, ages, by = "id")
print(matched)
  id name age
1  2  Ben  25
2  3   Cy  30

Use merge(people, ages, by = "id", all.x = TRUE) when the result must retain every person, including people without a matching age. The output order from a default merge is sorted by the key unless sort = FALSE is requested. The displayed table above is the supplied observed output for this example.

Conclusion

Choose rbind() to append rows with a shared structure, and choose dplyr::bind_rows() when row-binding inputs with differing columns and filling missing cells with NA is appropriate. Choose plyr::join() or merge() when related records should be matched using keys; base merge() is available without an additional package and provides options for keeping unmatched rows. Before combining larger data, check key uniqueness, column types, and whether the operation is a row bind or a join. Performance depends on the data and environment, so benchmark representative inputs before adopting a speed claim or custom optimization.