【问题标题】:Merge dataframes of different sizes合并不同大小的数据框
【发布时间】:2015-12-23 14:58:19
【问题描述】:

我有两个数据框d1d2分别为:

x   y  z
10  10 7
10  12 6
11  10 8
11  12 2
12  10 1
12  12 5

x  y  z
10 10 100
11 10 200
12 12 400

我想要类似的东西:

x   y  z
10  10 100
10  12 6
11  10 200
11  12 2
12  10 1
12  12 400

对于这个琐碎的问题,我真的很抱歉,我无法得到答案。

【问题讨论】:

  • 只删除 d1 和 rbind(d1, d2) 的第一行、第三行和最后一行
  • 您能否详细说明 10,10,7 发生了什么?前两列是“键”,第三列是“值”吗?
  • 亲爱的 MLavoie,这只是一个例子。真实数据更大。
  • 亲爱的 mlt,x 和 y 是经度和纬度的一种,z 是值
  • 我的意思是对于给定的 x&y,它可以是多值的吗?并考虑dput and this faq

标签: r dataframe


【解决方案1】:

根据您的描述,我了解到您想在 xy 匹配时将 d1 中的 z 值替换为 d2 中的 z 值。

使用基础 R:

d3 <- merge(d1, d2, by = c("x","y"), all.x = TRUE)
d3[is.na(d3$z.y),"z.y"] <- d3[is.na(d3$z.y),"z.x"]
d3 <- d3[,-3]
names(d3)[3] <- "z"

给出:

> d3
   x  y   z
1 10 10 100
2 10 12   6
3 11 10 200
4 11 12   2
5 12 10   1
6 12 12 400

使用data.table-包:

library(data.table)

setDT(d1) # convert the data.frame to a data.table
setDT(d2) # idem

# join the two data.table's and replace the values
d1[d2, on = .(x, y), z := i.z]

或一口气:

setDT(d1)[setDT(d2), on = .(x, y), z := i.z]

给出:

> d1
    x  y   z
1: 10 10 100
2: 10 12   6
3: 11 10 200
4: 11 12   2
5: 12 10   1
6: 12 12 400

使用 dplyr 包:

d3 <- left_join(d1, d2, by = c("x","y")) %>%
  mutate(z.y = ifelse(is.na(z.y), z.x, z.y)) %>%
  select(-z.x) %>%
  rename(z = z.y)

由于release 0.5.0,您还可以为此使用coalesce-函数(感谢Laurent Hostert for bringing it to my attention):

d3 <- left_join(d1, d2, by = c("x","y")) %>% 
  mutate(z = coalesce(z.y, z.x)) %>% 
  select(-c(z.x, z.y))

【讨论】:

  • @Pankajthanx;我还添加了一个dplyr 替代
  • @Jaap 我添加了我的答案以扩展您的示例,见下文
  • @Jaap 在 dplyr 版本 v0.5.0 (github.com/tidyverse/dplyr/releases/tag/v0.5.0) 中添加了 coalesce 函数。这可以简化您的 dplyr 解决方案:d3 &lt;- left_join(d1, d2, by = c("x","y")) %&gt;% mutate(z = coalesce(z.y, z.x)) %&gt;% select(-c(z.x, z.y))
  • @LaurenHostert 谢谢通知!我现在已将其包含在我的答案中。
【解决方案2】:

在优秀的@Jaap answer wrt data.table之上

在 data.table 中,您可以使用键连接,而使用 data.table 使用键完成的任何操作都是最快的选择。您甚至可以有不同的列名,请参见下面的修改示例。

顺带一提,数据:

x  y  z
10 10 100
11 10 200
12 12 400

x  q  z
10  10 7
10  12 6
11  10 8
11  12 2
12  10 1
12  12 5

和代码:

library(data.table)

d1 <- fread("d1.csv", sep=" ")
d2 <- fread("d2.csv", sep=" ")

# here is data.table keys magic
# note different column names
setkey(d1, x, q)
setkey(d2, x, y)

q <- d2[d1][is.na(z), z := i.z][, i.z := NULL]

print(q)

结果:

    x  y   z
1: 10 10 100
2: 10 12   6
3: 11 10 200
4: 11 12   2
5: 12 10   1
6: 12 12 400

【讨论】:

  • 亲爱的 Severin Pappadeux,感谢您提出改进建议。
  • 使用on时也可以加入不同的列名:d2[d1, on=c("x"="x","y"="q")]。使用development version of data.table (1.9.7),您可以将其缩短为d2[d1, on=c("x","y"="q")]。不确定设置密钥是否比使用on 更快。你测试了吗?
  • 很好,但这首先返回一个全新的 data.table 然后更新它——所有这些都只是为了添加一列(= 内存效率低下)。请参阅 Jaap 的更新答案。
【解决方案3】:

听起来您想确保每个 xy 值只有一个 z 值。主要问题是如何选择与之关联的 z 值。根据描述,我猜您要么希望始终覆盖第二个数据框,要么希望取最大值。

从原始数据开始:

df1 <- structure(list(x = c(10L, 10L, 11L, 11L, 12L, 12L), y = c(10L, 12L, 10L, 12L, 10L, 12L), z = c(7L, 6L, 8L, 2L, 1L, 5L)), .Names = c("x", "y", "z"), class = "data.frame", row.names = c(NA, -6L))
df2 <- structure(list(x = 10:12, y = c(10L, 10L, 12L), z = c(100L, 200L,400L)), .Names = c("x", "y", "z"), class = "data.frame", row.names = c(NA,-3L))

如果这是您想要的最大值,那么您可能只想简单地组合两个帧,然后为每个 xy 提取最大值:

merged.df <- aggregate(z ~ x + y, data = rbind(df1, df2), max)

如果您希望第二个数据框覆盖第一个数据框,那么您将使用最后一个匹配的值进行聚合

merged.df <- aggregate(z ~ x+ y, data=rbind(df1, df2), function(d) tail(d, n=1))

如果除了z 之外还有很多列,那么我只能假设您想要后一种行为。为此,您最好使用data.tabledplyr 之类的库。在dplyr 中,它看起来像这样

require(dplyr)
merged.df <- rbind(df1, df2) %>% group_by(x, y) %>% summarise_each(funs(last))

data.table 看起来像

require(data.table)
merged.df <- setDT(rbind(df1, df2))[, lapply(.SD, last), .(x,y)]

【讨论】:

  • 尊敬的 user295691,非常感谢您分享有用的信息。
【解决方案4】:

或者使用merge 这个update-join 可以在base 中通过使用matchwhich 来查找用于子设置的索引表格和interaction 以从两个中生成一个键向量。

这样,d1ordersize 都不会改变。如果d2 中的key 出现两次,则第一次出现将用于更新d1

d1 <- read.table(header=TRUE, text="x   y  z
10  10 7
10  12 6
11  10 8
11  12 2
12  10 1
12  12 5")
d2 <- read.table(header=TRUE, text="x  y  z
10 10 100
11 10 200
12 12 400")

key <- c("x", "y") #define which columns are used as matching key
idx <- match(interaction(d2[key]), interaction(d1[key])) #find where it matches
d1$z[idx] <- d2$z #make the update

d1 #show result
#   x  y   z
#1 10 10 100
#2 10 12   6
#3 11 10 200
#4 11 12   2
#5 12 10   1
#6 12 12 400

您可以检查 d1 和 d2 之间是否匹配,例如:

idx <- match(interaction(d1[key]), interaction(d2[key]))
idxn <- which(!is.na(idx)) #find where it does not match
d1$z[idxn] <- d2$z[idx[idxn]]

idx <- match(interaction(d2[key]), interaction(d1[key]))
idxn <- which(!is.na(idx))
d1$z[idx[idxn]] <- d2$z[idxn]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-24
    • 1970-01-01
    相关资源
    最近更新 更多