【问题标题】:Merging 2 Data.frame by equal distribution of Rows in R通过 R 中行的均等分布合并 2 Data.frame
【发布时间】:2020-10-13 14:32:08
【问题描述】:

我有两个数据框 df_1df_2 超过 5000 个观察值(行)。我想基于DateMcode 两个相似的列合并它们,以使行在两个数据帧中均匀分布。详情见下文。

>df_1
 Date      Mcode    TNo. BSize
1  1/8/2014 3R72B7K8ZN 1426576   7.2
2  1/8/2014 3R72B7K8ZN 1426578   7.5
3  1/8/2014 3R72B7K8ZN 1426579   7.5
4  1/8/2014 8R55BNW9H5 1426581   7.2
5  1/8/2014 8R55BNW9H5 1426582   7.5
6  1/8/2014 8R55BNW9H5 1426584   7.5
7  1/8/2014 3R72B7K8ZN 1426606   7.5
8  1/8/2014 3R72B7K8ZN 1426610   7.2
9  1/8/2014 8R55BNW9H5 1426621   7.5
10 1/8/2014 8R55BNW9H5 1426624   7.5
11 2/8/2014 4R72B7K9ZN 1426626   7.5
12 2/8/2014 4R72B7K9ZN 1426627   7.5
13 2/8/2014 8R55BNW9H5 1426638   7.2
14 2/8/2014 8R55BNW9H5 1426639   7.2
15 2/8/2014 4R60B6K6ZN 1426699   7.5
16 3/8/2014 4R60B6K6ZN 1426701   1.5
17 3/8/2014 4R72B7K9ZN 1426703   7.5
18 3/8/2014 4R60B6K6ZN 1426704   7.5
19 3/8/2014 4R72B7K9ZN 1426705   7.5
20 3/8/2014 4R72B7K9ZN 1426706   7.2

类似的第二个数据框如下。

>df_2
   Date      Mcode X28days X7days
1  1/8/2014 3R72B7K8ZN    64.0   51.1
2  1/8/2014 3R72B7K8ZN    65.0   51.6
3  1/8/2014 8R55BNW9H5    75.4   58.4
4  1/8/2014 8R55BNW9H5    78.7   57.1
5  2/8/2014 4R72B7K9ZN    75.7   58.8
6  2/8/2014 4R72B7K9ZN    73.9   56.9
7  2/8/2014 8R55BNW9H5    77.3   60.8
8  2/8/2014 4R60B6K6ZN    62.6   48.5
9  3/8/2014 4R72B7K9ZN    71.2   56.1
10 4/8/2014 4R60B6K6ZN    59.3   46.8
11 4/8/2014 4R60B6K7ZN    68.5   51.2

我想合并df_1df_2,这样得到的df_3(与df_1 的行数相同)应如下所示

>df_3
       Date      Mcode    TNo. BSize X28days X7days
1  1/8/2014 3R72B7K8ZN 1426576   7.2    64.0   51.1
2  1/8/2014 3R72B7K8ZN 1426578   7.5    64.0   51.1
3  1/8/2014 3R72B7K8ZN 1426579   7.5    64.0   51.1
4  1/8/2014 8R55BNW9H5 1426581   7.2    75.4   58.4
5  1/8/2014 8R55BNW9H5 1426582   7.5    75.4   58.4
6  1/8/2014 8R55BNW9H5 1426584   7.5    75.4   58.4
7  1/8/2014 3R72B7K8ZN 1426606   7.5    65.0   51.6
8  1/8/2014 3R72B7K8ZN 1426610   7.2    65.0   51.6
9  1/8/2014 8R55BNW9H5 1426621   7.5    78.7   57.1
10 1/8/2014 8R55BNW9H5 1426624   7.5    78.7   57.1
11 2/8/2014 4R72B7K9ZN 1426626   7.5    75.7   58.8
12 2/8/2014 4R72B7K9ZN 1426627   7.5    75.7   58.8
13 2/8/2014 8R55BNW9H5 1426638   7.2    77.3   60.8
14 2/8/2014 8R55BNW9H5 1426639   7.2    77.3   60.8
15 2/8/2014 4R60B6K6ZN 1426699   7.5    62.6   48.5
16 3/8/2014 4R60B6K6ZN 1426701   1.5      NA     NA
17 3/8/2014 4R72B7K9ZN 1426703   7.5    71.2   56.1
18 3/8/2014 4R60B6K6ZN 1426704   7.5      NA     NA
19 3/8/2014 4R72B7K9ZN 1426705   7.5    71.2   56.1
20 3/8/2014 4R72B7K9ZN 1426706   7.2    71.2   56.1

如果我们运行df_3%>%filter(Date=="1/8/2014", Mcode=="3R72B7K8ZN"),它会给出


      Date      Mcode    TNo. BSize X28days X7days
1 1/8/2014 3R72B7K8ZN 1426576   7.2      64   51.1
2 1/8/2014 3R72B7K8ZN 1426578   7.5      64   51.1
3 1/8/2014 3R72B7K8ZN 1426579   7.5      64   51.1
4 1/8/2014 3R72B7K8ZN 1426606   7.5      65   51.6
5 1/8/2014 3R72B7K8ZN 1426610   7.2      65   51.6

df_2 的前两行平均分布在 df_3 的最终或合并数据集中。对于所有行都可以看到类似的合并模式。 笔记: 我希望这种类型的合并用于大小大于 30x5000(col x 行)的完整数据集。 在完整的数据中 日期是 2014 年和 2015 年(超过 700 个日期),Mcode 有 30 多种不同的类型。

谁能帮助我,我将不胜感激。

【问题讨论】:

  • 您提到“基于日期和 Mcode 两个相似的列合并它们”。但是看起来两个数据帧都有重复的值,你希望合并的结果与第一个数据帧的行长相同吗?
  • 这是主要问题,重复导致行的平均分布问题,这就是为什么我在这里,是的,最终数据的长度应该等于第一个更大的数据帧

标签: r dplyr merge mergesort


【解决方案1】:

解决此问题的一种方法是向两个数据框添加一个额外的 id 列。
我在这里称它为obs_id。此 ID 在 DateMcode 的每组中设置,以计算到各自其他数据帧中的最大观察数,然后从 1“重置”。
如下所示:

library(dplyr)

df_1a <- df_1 %>%
  left_join(
    df_2 %>% count(Date, Mcode, name = "df_2_obs_n"),
    by = c("Date", "Mcode")
  ) %>%
  group_by(Date, Mcode) %>%
  mutate(
    obs_id = first(df_2_obs_n) %>%
      coalesce(0) %>%
      seq() %>%
      rep(length.out = n())
  ) %>%
  ungroup() %>%
  select(-df_2_obs_n)

df_2a <- df_2 %>%
  left_join(
    df_1a %>% count(Date, Mcode, name = "df_1_obs_n"),
    by = c("Date", "Mcode")
  ) %>%
  group_by(Date, Mcode) %>%
  mutate(
    obs_id = first(df_1_obs_n) %>%
      coalesce(0) %>%
      seq() %>%
      rep(length.out = n())
  ) %>%
  ungroup() %>%
  select(-df_1_obs_n)

对于您的 Date=="1/8/2014", Mcode=="3R72B7K8ZN" 示例组,这会生成如下所示的列:

> df_1a %>% filter(Date=="1/8/2014", Mcode=="3R72B7K8ZN")
# A tibble: 5 x 5
  Date     Mcode         TNo. BSize obs_id
  <chr>    <chr>        <int> <dbl>  <int>
1 1/8/2014 3R72B7K8ZN 1426576   7.2      1
2 1/8/2014 3R72B7K8ZN 1426578   7.5      2
3 1/8/2014 3R72B7K8ZN 1426579   7.5      1
4 1/8/2014 3R72B7K8ZN 1426606   7.5      2
5 1/8/2014 3R72B7K8ZN 1426610   7.2      1

> df_2a %>% filter(Date=="1/8/2014", Mcode=="3R72B7K8ZN")
# A tibble: 2 x 5
  Date     Mcode      X28days X7days obs_id
  <chr>    <chr>        <dbl>  <dbl>  <int>
1 1/8/2014 3R72B7K8ZN      64   51.1      1
2 1/8/2014 3R72B7K8ZN      65   51.6      2

现在,您可以基于该列离开联接,您将看到来自df_2a 的列“分布均匀”,至少与您预期的一样多。

df_3a <- df_1a %>%
  left_join(df_2a, by = c("Date", "Mcode", "obs_id"))

> df_3a %>% filter(Date=="1/8/2014", Mcode=="3R72B7K8ZN")
# A tibble: 5 x 7
  Date     Mcode         TNo. BSize obs_id X28days X7days
  <chr>    <chr>        <int> <dbl>  <int>   <dbl>  <dbl>
1 1/8/2014 3R72B7K8ZN 1426576   7.2      1      64   51.1
2 1/8/2014 3R72B7K8ZN 1426578   7.5      2      65   51.6
3 1/8/2014 3R72B7K8ZN 1426579   7.5      1      64   51.1
4 1/8/2014 3R72B7K8ZN 1426606   7.5      2      65   51.6
5 1/8/2014 3R72B7K8ZN 1426610   7.2      1      64   51.1

由于obs_iddf_1a 中的模式1,2,1,2,1 中重复,df_2a 中的表行连接顺序与您上面描述的df_3 不同。如果这是一个问题,您可以像这样调整 rep(...) 调用:

df_1b <- df_1 %>%
  left_join(
    df_2 %>%
      count(Date, Mcode, name = "df_2_obs_n"),
    by = c("Date", "Mcode")
  ) %>%
  group_by(Date, Mcode) %>%
  mutate(
    df_2_obs_n = coalesce(df_2_obs_n, 1),
    obs_id = first(df_2_obs_n) %>%
      seq() %>%
      rep(length.out = n(), each = ceiling(n()/first(df_2_obs_n)))
  ) %>%
  ungroup() %>%
  select(-df_2_obs_n)

df_2b <- df_2 %>%
  left_join(
    df_1a %>%
      count(Date, Mcode, name = "df_1_obs_n"),
    by = c("Date", "Mcode")
  ) %>%
  group_by(Date, Mcode) %>%
  mutate(
    df_1_obs_n = coalesce(df_1_obs_n, 1),
    obs_id = first(df_1_obs_n) %>%
      seq() %>%
      rep(length.out = n(), each = ceiling(n()/first(df_1_obs_n)))
  ) %>%
  ungroup() %>%
  select(-df_1_obs_n)

现在,obs_id 重复模式是 1,1,1,2,2,您将得到您描述的结果。

df_3b <- df_1b %>%
    left_join(df_2b, by = c("Date", "Mcode", "obs_id"))

> df_3b %>% filter(Date=="1/8/2014", Mcode=="3R72B7K8ZN")
# A tibble: 5 x 7
  Date     Mcode         TNo. BSize obs_id X28days X7days
  <chr>    <chr>        <int> <dbl>  <int>   <dbl>  <dbl>
1 1/8/2014 3R72B7K8ZN 1426576   7.2      1      64   51.1
2 1/8/2014 3R72B7K8ZN 1426578   7.5      1      64   51.1
3 1/8/2014 3R72B7K8ZN 1426579   7.5      1      64   51.1
4 1/8/2014 3R72B7K8ZN 1426606   7.5      2      65   51.6
5 1/8/2014 3R72B7K8ZN 1426610   7.2      2      65   51.6

【讨论】:

  • 你太棒了,先生,非常感谢,我是 R 的初学者,所以很难消化这么大的代码,但我试过了。它的工作,现在我要玩来完全理解它。再次感谢你
  • 很高兴听到。如果您还有其他问题,请告诉我。另外,如果答案解决了您的问题,请随时投票并接受它:)
  • 哦抱歉忘记接受和投票了,我是新的@stack,现在已经完成了谢谢
  • 先生,它在其中一个数据集中运行,但现在它给出了一个错误,就像我第一次运行时它给出错误 df_1a % left_join( df_2 %>% count(Date,混合,名称=“df_2_obs_n”),按= c(“日期”,“混合”))%>% group_by(日期,混合)%>% 变异(obs_id = first(df_2_obs_n)%>% 合并(0)% >% seq() %>% rep(length.out = n()) ) %>% ungroup() %>% select(-df_2_obs_n) 错误:参数 2 必须是整数向量,而不是双精度向量
  • 嗯,不知道为什么会发生这种情况,如果你没有添加一些中间步骤.. 最好,你将first(df_2_obs_n) 包装在as.integer 中,并将@中的 0 更改为整数类型的 0L 987654341@(所以,coalesce(0L))以避免类型冲突。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-12-04
  • 2017-03-14
  • 1970-01-01
  • 2013-01-24
  • 1970-01-01
  • 1970-01-01
  • 2014-08-12
相关资源
最近更新 更多