如何合并同一数据框的多个列?

时间:2016-11-24 09:17:07

标签: r merge

我有一个大数据框,包含几个探针执行的不同测量。

测量的时间并不完全相同。由于我想在给定时间比较两个测量值并在动画中绘制它们,我需要将数据“同步”。

这是我得到的数据帧的一个例子(在现实生活中,我有更多的列,我直接从文本文件中读取):

time1.in.s <- seq(0.010, 100, length.out = 100)
time2.in.s <- seq(0.022, 100, length.out = 100)
data1 <- seq(-10, 100, length.out = 100)
data2 <- seq(-25, 80, length.out = 100)

my.df <- data.frame(time1.in.s, data1, time2.in.s, data2)

给出了:

    time1.in.s      data1 time2.in.s       data2
1         0.01 -10.000000   0.022000 -25.0000000
2         1.02  -8.888889   1.031879 -23.9393939
3         2.03  -7.777778   2.041758 -22.8787879
4         3.04  -6.666667   3.051636 -21.8181818
5         4.05  -5.555556   4.061515 -20.7575758
6         5.06  -4.444444   5.071394 -19.6969697

我想要做的是在一个“时间”列中合并两个timeX.in.s列。在数据不可用的情况下,我会使用na.approx(my.df$data1, x = my.df$time)

之类的内容来填写

提供此代码以便您可以重现该问题,但在现实生活中,time1.in.s,time2.in.s,data1和data2不能单独提供。我实际做的是my.df <- read.table(my.file, header = TRUE),我得到了相同的结果。因此,我无法直接构建单独的数据框,我需要手动分割一个大数据框:

df.list <- list()
  for (i in seq(1, ncol(my.df), 2)) {
    df.list[[ceiling(i/2)]] <- data.frame(time = my.df[, i], data = my.df[, i+1])
  }

然后逐个合并数据框:

merged.df <- data.frame(time = as.numeric(NA), data = as.numeric(NA))
  for (i in 1:length(df.list)) {
    merged.df <- merge(merged.df, df.list[[i]], by = "time", all = TRUE)
  }

最后填补空白:

merged.df$data.y <- na.approx(merged.df$data.y, x = merged.df$time, na.rm = FALSE)

这肯定有效(除了列的名称是一个很大的混乱)。但它很麻烦,对我来说看起来不太对劲。有更简单的方法吗?

以下是使用上述命令获得的结果:

> head(merged.df)
      time data.x     data.y      data
1 0.010000     NA -10.000000        NA
2 0.022000     NA  -9.986799 -25.00000
3 1.020000     NA  -8.888889        NA
4 1.031879     NA  -8.875821 -23.93939
5 2.030000     NA  -7.777778        NA
6 2.041758     NA  -7.764843 -22.87879

列data.x来自最初的empty merged.df。它可以被倾倒。 列data.y是my.df $ data1列。 在上面的数据框中,我没有对列数据使用na.approx命令(对应于my.df $ data2列)

关于OmaymaS提议的解决方案的补充说明:

为了使这项工作在一般情况下(即任意数量的列),我所做的是以下内容。首先,我定义了一个6列数据框:

time1.in.s <- seq(0.010, 100, length.out = 100)
time2.in.s <- seq(0.022, 100, length.out = 100)
time3.in.s <- seq(0.017, 99.8, length.out = 100)
data1 <- seq(-10, 100, length.out = 100)
data2 <- seq(-25, 80, length.out = 100)
data3 <- seq(-15, 70, length.out = 100)

my.df <- data.frame(time1.in.s, data1, time2.in.s, data2, time3.in.s, data3)

这导致:

head(my.df)
  time1.in.s      data1 time2.in.s     data2 time3.in.s     data3
1       0.01 -10.000000   0.022000 -25.00000   0.017000 -15.00000
2       1.02  -8.888889   1.031879 -23.93939   1.024909 -14.14141
3       2.03  -7.777778   2.041758 -22.87879   2.032818 -13.28283
4       3.04  -6.666667   3.051636 -21.81818   3.040727 -12.42424
5       4.05  -5.555556   4.061515 -20.75758   4.048636 -11.56566
6       5.06  -4.444444   5.071394 -19.69697   5.056545 -10.70707

我将包含时间的所有列的名称更改为相同的名称(这样我就不必告诉merge函数合并哪个列by):

colnames(my.df)[seq(1, ncol(my.df), 2)] <- "Time"

然后我循环一个略微修改的Reduce函数:

df.merged <- my.df[, 1:2]

for (i in seq(3, ncol(my.df), 2)) {
  df.merged <- Reduce(function(x,y) merge(x,y,
                                          all = TRUE),
                      list(df.merged,
                           my.df[, i:(i+1)])
  )
}

这给出了:

> head(df.merged)
      Time      data1     data2     data3
1 0.010000 -10.000000        NA        NA
2 0.017000         NA        NA -15.00000
3 0.022000         NA -25.00000        NA
4 1.020000  -8.888889        NA        NA
5 1.024909         NA        NA -14.14141
6 1.031879         NA -23.93939        NA

最后,我应用了na.approx函数:

df.interp <- df.merged
df.interp[, 2:ncol(df.interp)] <- na.approx(df.interp[, 2:ncol(df.interp)],
                                            x = df.interp$Time,
                                             na.rm = FALSE)

以下是最终结果:

> head(df.interp)
      Time      data1     data2     data3
1 0.010000 -10.000000        NA        NA
2 0.017000  -9.992299        NA -15.00000
3 0.022000  -9.986799 -25.00000 -14.99574
4 1.020000  -8.888889 -23.95187 -14.14560
5 1.024909  -8.883488 -23.94671 -14.14141
6 1.031879  -8.875821 -23.93939 -14.13548

我仍然在某些数据列的开头有NAs,但我可以使用na.omit函数删除它们。

2 个答案:

答案 0 :(得分:2)

尝试合并,它应该可以帮助您实现所需:

首先:创建两个包含数据和相应时间的数据框:

df1 <- data.frame(time1.in.s, data1)
df2 <- data.frame(time2.in.s, data2)

第二步:合并两个数据帧,使用by.x和by.y指定要使用的列,并包括所有值:

df.merged <- merge(df1,df2,
      by.x = "time1.in.s",
      by.y = "time2.in.s",
      all.x = TRUE,
      all.y = TRUE)

注意:根据Sotos建议澄清:

all.x = TRUE,
all.y = TRUE

类似于

all = TRUE

因此,如果要从另一个中不存在的数据帧中排除值,可以将all.x或all.y设置为FALSE。

现在您将有时间在列中,您可以根据需要重命名列。

> head(df.merged)
  time1.in.s      data1     data2
1   0.010000 -10.000000        NA
2   0.022000         NA -25.00000
3   1.020000  -8.888889        NA
4   1.031879         NA -23.93939
5   2.030000  -7.777778        NA
6   2.041758         NA -22.87879

编辑:如果您想在多个 timen.in.s- datan 的多列上应用此功能,可以尝试按如下方式进行缩减,可以在列表中添加多个选项,并且所有选择都将根据时间列合并,假设它始终是select中的第一个。

df.merged <- Reduce(function(x,y) merge(x,y,
                   by.x = names(x)[1],
                   by.y = names(y)[1],
                   all = TRUE),
   list(select(my.df,time1.in.s, data1),
        select(my.df,time2.in.s, data2))
   )

> head(df.merged)
  time1.in.s      data1     data2
1   0.010000 -10.000000        NA
2   0.022000         NA -25.00000
3   1.020000  -8.888889        NA
4   1.031879         NA -23.93939
5   2.030000  -7.777778        NA
6   2.041758         NA -22.87879

附加说明:

如果您想使用列'indecies,可以使用:

df.merged <- Reduce(function(x,y) merge(x,y,
                                        by.x = names(x)[1],
                                        by.y = names(y)[1],
                                        all = TRUE),
                    list(select(my.df,1,2),
                         select(my.df,3,4))
)

同样如果列的名称一致,并且您想自动构建列表,则可以创建一个取整数并返回要选择的列名称的函数: p>

getDF <- function(x)
{
        c1 <- paste0("time",x,".in.s")
        c2 <- paste0("data",x)
        return(c(c1,c2))
}

例如:

> getDF(1)
[1] "time1.in.s" "data1"

然后你可以在reduce:

中使用它
df.merged <- Reduce(function(x,y) merge(x,y,
                                        by.x = names(x)[1],
                                        by.y = names(y)[1],
                                        all = TRUE),
                    list(my.df[,getDF(1)],
                         my.df[,getDF(2)])
)

答案 1 :(得分:0)

一些代码。

我假设您希望将每CREATE TABLE mytable( ExtractTypeNum INTEGER NOT NULL --PRIMARY KEY ,FileOrderNum VARCHAR(11) ,PrevFileOrderNum VARCHAR(11) ,NextFileOrderNum VARCHAR(11) ,rownum1 INTEGER ,Statusflag1 VARCHAR(9) ); INSERT INTO mytable(ExtractTypeNum,FileOrderNum,PrevFileOrderNum,NextFileOrderNum,rownum1,Statusflag1) VALUES (1,'2016-09-191',NULL,'2016-09-192',1,'IsInitial'); INSERT INTO mytable(ExtractTypeNum,FileOrderNum,PrevFileOrderNum,NextFileOrderNum,rownum1,Statusflag1) VALUES (2,'2016-09-192','2016-09-191','2016-09-201',2,NULL); INSERT INTO mytable(ExtractTypeNum,FileOrderNum,PrevFileOrderNum,NextFileOrderNum,rownum1,Statusflag1) VALUES (3,'2016-09-201','2016-09-192','2016-09-211',3,NULL); select 'Update Table Xyz Set Abc='+Convert(varchar(25),rownum1)+' ' as X,* from myTable 列分开

data.frame