绑定不同长度的数据帧(无 cbind,无合并)
Binding dataframes of different length (no cbind, no merge)
我正在尝试并排显示多个数据框以比较某些条目。但是,它们的行数不同,我希望每个数据框的顺序完全相同。
我尝试使用 cbind
由于行数不同而无法使用。我使用 merge
将两个 dfs 绑定在一起,然后再次合并它们,但是当我这样做时它们改变了顺序,当我总共有 5 个以上的 dfs 时合并两个 dfs 似乎效率低下。
示例:
df <- data.frame(v=1:5, x=sample(LETTERS[1:5],5))
df
v x
1 1 E
2 2 B
3 3 D
4 4 C
5 5 A
df2 <- data.frame(m=7:10, n=sample(LETTERS[6:9],4))
df2
m n
1 7 G
2 8 I
3 9 F
4 10 H
然后我点了df2
df2 <- df2[order(df2$m, decreasing = TRUE),]
df2
m n
4 10 F
3 9 I
2 8 H
1 7 G
预期输出:
v x m n
1 1 E 10 F
2 2 B 9 I
3 3 D 8 H
4 4 C 7 G
5 5 A NA NA
正如我所说,我有两个以上的dfs,dfs的顺序应该保持不变。任何帮助将不胜感激!
library(plyr)
combined <- rbind.fill(df[c("v", "x")], df2[c("m", "n")])
这是你想要的吗?
编辑:如果有多个 df
。这样做
- 创建除第一个以外的所有 df 的列表
- 使用
purrr::reduce
将所有这些连接在一起
- 在
.init
参数中首先传递 df
。
df2 <- data.frame(m=7:10, n=sample(LETTERS[6:9],4))
df <- data.frame(v=1:5, x=sample(LETTERS[1:5],5))
df3 <- data.frame(bb = 101:110, cc = sample(letters, 10))
reduce(list(df2, df3), .init = df %>% mutate(id = row_number()) , ~full_join(.x, .y %>% mutate(id = row_number()), by = "id" )) %>%
select(-id)
v x m n bb cc
1 1 A 10 I 101 u
2 2 C 9 H 102 v
3 3 D 8 G 103 n
4 4 E 7 F 104 w
5 5 B NA <NA> 105 s
6 NA <NA> NA <NA> 106 y
7 NA <NA> NA <NA> 107 g
8 NA <NA> NA <NA> 108 i
9 NA <NA> NA <NA> 109 p
10 NA <NA> NA <NA> 110 h
较早的答案:在两个 df
中创建一个虚拟列 id
并使用 full_join
full_join(df %>% mutate(id = row_number()), df2 %>% mutate(id = row_number()), by = "id") %>%
select(-id)
v x m n
1 1 A 10 I
2 2 C 9 H
3 3 D 8 G
4 4 E 7 F
5 5 B NA <NA>
随机数种子不同导致结果与预期不同
或在 BaseR 中
merge(transform(df, id = seq_len(nrow(df))), transform(df2, id = seq_len(nrow(df2))), all = T)
id v x m n
1 1 1 A 10 I
2 2 2 C 9 H
3 3 3 D 8 G
4 4 4 E 7 F
5 5 5 B NA <NA>
通过子集 []
简单地删除多余的列
merge(transform(df, id = seq_len(nrow(df))), transform(df2, id = seq_len(nrow(df2))), all = T)[-1]
v x m n
1 1 A 10 I
2 2 C 9 H
3 3 D 8 G
4 4 E 7 F
5 5 B NA <NA>
基础 R 方法:
将数据帧放入列表中,获取行数最大的数据帧,将 NA
附加到行数较少的数据和 cbind
.
list_df <- list(df, df2)
n_r <- seq_len(max(sapply(list_df, nrow)))
result <- do.call(cbind, lapply(list_df, `[`, n_r, ))
result
# v x m n
#1 1 C 10 F
#2 2 B 9 H
#3 3 E 8 G
#4 4 D 7 I
#5 5 A NA <NA>
另一种基础 R 方法,但对于合并,您需要:
- 添加
sort
参数以确保结果不会被排序
- 从数据框中删除行名称
- 添加
all
参数以确保使用所有行,
[-1]
是去掉merge 添加的行名列
示例:
set.seed(123)
df1 <- data.frame(v = 1:5,
x = sample(LETTERS[1:5], 5))
df1
#> v x
#> 1 1 A
#> 2 2 B
#> 3 3 D
#> 4 4 C
#> 5 5 E
df2 <- data.frame(m = 7:10,
n = sample(LETTERS[6:9], 4))
df2
#> m n
#> 1 7 G
#> 2 8 H
#> 3 9 I
#> 4 10 F
df2 <- df2[order(df2$m, decreasing = TRUE),]
df2
#> m n
#> 4 10 F
#> 3 9 I
#> 2 8 H
#> 1 7 G
merge(data.frame(df1, row.names = NULL),
data.frame(df2, row.names = NULL),
by = 0,
all = TRUE,
sort = FALSE)[-1]
#> v x m n
#> 1 1 A 10 F
#> 2 2 B 9 I
#> 3 3 D 8 H
#> 4 4 C 7 G
#> 5 5 E NA <NA>
如果您需要超过 2 个数据帧,您可以使用 Reduce
。
df3 <- data.frame(a = 1:7,
z = sample(LETTERS[1:7], 7))
Reduce(function(x,y) merge(x = x, y = y, by = 0, all = TRUE, sort = FALSE)[-1],
list(data.frame(df1, row.names = NULL),
data.frame(df2, row.names = NULL),
data.frame(df3, row.names = NULL)))
#> v x m n a z
#> 1 1 C 10 I 1 F
#> 2 2 B 9 F 2 G
#> 3 3 E 8 H 3 A
#> 4 4 D 7 G 4 B
#> 5 5 A NA <NA> 5 C
#> 6 NA <NA> NA <NA> 6 D
#> 7 NA <NA> NA <NA> 7 E
Created on 2021-04-22 by the reprex package (v2.0.0)
我正在尝试并排显示多个数据框以比较某些条目。但是,它们的行数不同,我希望每个数据框的顺序完全相同。
我尝试使用 cbind
由于行数不同而无法使用。我使用 merge
将两个 dfs 绑定在一起,然后再次合并它们,但是当我这样做时它们改变了顺序,当我总共有 5 个以上的 dfs 时合并两个 dfs 似乎效率低下。
示例:
df <- data.frame(v=1:5, x=sample(LETTERS[1:5],5))
df
v x
1 1 E
2 2 B
3 3 D
4 4 C
5 5 A
df2 <- data.frame(m=7:10, n=sample(LETTERS[6:9],4))
df2
m n
1 7 G
2 8 I
3 9 F
4 10 H
然后我点了df2
df2 <- df2[order(df2$m, decreasing = TRUE),]
df2
m n
4 10 F
3 9 I
2 8 H
1 7 G
预期输出:
v x m n
1 1 E 10 F
2 2 B 9 I
3 3 D 8 H
4 4 C 7 G
5 5 A NA NA
正如我所说,我有两个以上的dfs,dfs的顺序应该保持不变。任何帮助将不胜感激!
library(plyr)
combined <- rbind.fill(df[c("v", "x")], df2[c("m", "n")])
这是你想要的吗?
编辑:如果有多个 df
。这样做
- 创建除第一个以外的所有 df 的列表
- 使用
purrr::reduce
将所有这些连接在一起 - 在
.init
参数中首先传递df
。
df2 <- data.frame(m=7:10, n=sample(LETTERS[6:9],4))
df <- data.frame(v=1:5, x=sample(LETTERS[1:5],5))
df3 <- data.frame(bb = 101:110, cc = sample(letters, 10))
reduce(list(df2, df3), .init = df %>% mutate(id = row_number()) , ~full_join(.x, .y %>% mutate(id = row_number()), by = "id" )) %>%
select(-id)
v x m n bb cc
1 1 A 10 I 101 u
2 2 C 9 H 102 v
3 3 D 8 G 103 n
4 4 E 7 F 104 w
5 5 B NA <NA> 105 s
6 NA <NA> NA <NA> 106 y
7 NA <NA> NA <NA> 107 g
8 NA <NA> NA <NA> 108 i
9 NA <NA> NA <NA> 109 p
10 NA <NA> NA <NA> 110 h
较早的答案:在两个 df
中创建一个虚拟列 id
并使用 full_join
full_join(df %>% mutate(id = row_number()), df2 %>% mutate(id = row_number()), by = "id") %>%
select(-id)
v x m n
1 1 A 10 I
2 2 C 9 H
3 3 D 8 G
4 4 E 7 F
5 5 B NA <NA>
随机数种子不同导致结果与预期不同
或在 BaseR 中
merge(transform(df, id = seq_len(nrow(df))), transform(df2, id = seq_len(nrow(df2))), all = T)
id v x m n
1 1 1 A 10 I
2 2 2 C 9 H
3 3 3 D 8 G
4 4 4 E 7 F
5 5 5 B NA <NA>
通过子集 []
简单地删除多余的列merge(transform(df, id = seq_len(nrow(df))), transform(df2, id = seq_len(nrow(df2))), all = T)[-1]
v x m n
1 1 A 10 I
2 2 C 9 H
3 3 D 8 G
4 4 E 7 F
5 5 B NA <NA>
基础 R 方法:
将数据帧放入列表中,获取行数最大的数据帧,将 NA
附加到行数较少的数据和 cbind
.
list_df <- list(df, df2)
n_r <- seq_len(max(sapply(list_df, nrow)))
result <- do.call(cbind, lapply(list_df, `[`, n_r, ))
result
# v x m n
#1 1 C 10 F
#2 2 B 9 H
#3 3 E 8 G
#4 4 D 7 I
#5 5 A NA <NA>
另一种基础 R 方法,但对于合并,您需要:
- 添加
sort
参数以确保结果不会被排序 - 从数据框中删除行名称
- 添加
all
参数以确保使用所有行, [-1]
是去掉merge 添加的行名列
示例:
set.seed(123)
df1 <- data.frame(v = 1:5,
x = sample(LETTERS[1:5], 5))
df1
#> v x
#> 1 1 A
#> 2 2 B
#> 3 3 D
#> 4 4 C
#> 5 5 E
df2 <- data.frame(m = 7:10,
n = sample(LETTERS[6:9], 4))
df2
#> m n
#> 1 7 G
#> 2 8 H
#> 3 9 I
#> 4 10 F
df2 <- df2[order(df2$m, decreasing = TRUE),]
df2
#> m n
#> 4 10 F
#> 3 9 I
#> 2 8 H
#> 1 7 G
merge(data.frame(df1, row.names = NULL),
data.frame(df2, row.names = NULL),
by = 0,
all = TRUE,
sort = FALSE)[-1]
#> v x m n
#> 1 1 A 10 F
#> 2 2 B 9 I
#> 3 3 D 8 H
#> 4 4 C 7 G
#> 5 5 E NA <NA>
如果您需要超过 2 个数据帧,您可以使用 Reduce
。
df3 <- data.frame(a = 1:7,
z = sample(LETTERS[1:7], 7))
Reduce(function(x,y) merge(x = x, y = y, by = 0, all = TRUE, sort = FALSE)[-1],
list(data.frame(df1, row.names = NULL),
data.frame(df2, row.names = NULL),
data.frame(df3, row.names = NULL)))
#> v x m n a z
#> 1 1 C 10 I 1 F
#> 2 2 B 9 F 2 G
#> 3 3 E 8 H 3 A
#> 4 4 D 7 G 4 B
#> 5 5 A NA <NA> 5 C
#> 6 NA <NA> NA <NA> 6 D
#> 7 NA <NA> NA <NA> 7 E
Created on 2021-04-22 by the reprex package (v2.0.0)