过滤具有多个条件的数据帧

时间:2017-06-24 08:55:05

标签: r dataframe

我有以下数据框(不包括value2):

condition condition1 date1      date2      value1 value2
A         X          2016-01-01 2016-02-01 1      2
A         X          2016-02-01 2016-03-01 2      NA
A         Y          2016-03-01 2016-04-01 3      NA
B         Z          2016-01-01 2016-02-01 4      3
B         Y          2016-02-01 2016-03-01 3      NA

我希望获得value2列,并使用以下代码:

for (i in length(df$condition)){
  df$value2[i] <- filter(df, condition == df$condition[i] & date1 == df$date2[i])$value1
}

但是,当NA参数中的一个在数据框中不匹配时,我无法传递date2值。

2 个答案:

答案 0 :(得分:2)

我认为你不应该在这里使用for循环,因为它会减慢你的代码速度。此外,使用dplyr更容易:

require(dplyr)
require(magrittr)

df %>%
  group_by(condition) %>%
  arrange(date1) %>%
  mutate(value2 = ifelse(as.character(date2) == lead(as.character(date1)), 
  lead(value1), NA)) %>%
  arrange(condition)

此代码将生成输出:

  condition      date1      date2 value1 value2
     <fctr>     <date>     <date>  <dbl>  <dbl>
1         A 2016-01-01 2016-02-01      1      2
2         A 2016-02-01 2016-03-01      2      3
3         A 2016-03-01 2016-04-01      3     NA
4         B 2016-01-01 2016-02-01      4      3
5         B 2016-02-01 2016-03-01      3     NA

请注意,对于您提供的数据,您可以删除ifelse部分:

df %>%
  group_by(condition) %>%
  arrange(date1) %>%
  mutate(value2 = lead(value1)) %>%
  arrange(condition)

我们可以通过group_by:

合并第二个条件
df %>%
  group_by(condition, condition1) %>%
  arrange(date1) %>%
  mutate(value2 = ifelse(as.character(date2) == lead(as.character(date1)), 
  lead(value1), NA)) %>%
  arrange(condition)

这将输出:

  condition condition1      date1      date2 value1 value2
     <fctr>     <fctr>     <date>     <date>  <dbl>  <dbl>
1         A          X 2016-01-01 2016-02-01      1      2
2         A          X 2016-02-01 2016-03-01      2     NA
3         A          Y 2016-03-01 2016-04-01      3     NA
4         B          Z 2016-01-01 2016-02-01      4     NA
5         B          Y 2016-02-01 2016-03-01      3     NA

答案 1 :(得分:1)

虽然这个问题已经有了一个例外答案,但我相信解决方案可以用比目前发布的代码更少的代码来实现。

OP有requested

  

我希望下一个月value1 condition位于同一行。

这只需要在lead()上分组应用value1功能。 lead()data.table包中提供了dplyr功能。

使用data.table,这将成为一个单行:

library(data.table)
data.table(DF)[, value2 := shift(value1, type = "lead"), by = condition][]
   condition condition1      date1      date2 value1 value2
1:         A          X 2016-01-01 2016-02-01      1      2
2:         A          X 2016-02-01 2016-03-01      2      3
3:         A          Y 2016-03-01 2016-04-01      3     NA
4:         B          Z 2016-01-01 2016-02-01      4      3
5:         B          Y 2016-02-01 2016-03-01      3     NA

dplyr变体与the accepted answer类似,但有些精简,例如,当magrittr已加载时,无需单独加载dplyr

library(dplyr)
DF %>% 
  group_by(condition) %>% 
  mutate(value2 = lead(value1))
# A tibble: 5 x 6
# Groups:   condition [2]
  condition condition1      date1      date2 value1 value2
      <chr>      <chr>     <date>     <date>  <int>  <int>
1         A          X 2016-01-01 2016-02-01      1      2
2         A          X 2016-02-01 2016-03-01      2      3
3         A          Y 2016-03-01 2016-04-01      3     NA
4         B          Z 2016-01-01 2016-02-01      4      3
5         B          Y 2016-02-01 2016-03-01      3     NA

请注意,默认情况下,lead()的两个变体都会使用NA填充缺失值。因此, no 需要额外的代码才能专门处理每个组的最后一行。

附录:OP提供的示例数据集已按conditiondate1排序。由于lead()取决于data.frame中行的顺序,因此可能值得确保正确的顺序是安全的:

带有订购的

data.table解决方案:

data.table(DF)[order(date1), value2 := shift(value1, type = "lead"), keyby = condition][]
带有排序的

dplyr变体:

DF %>% 
  group_by(condition) %>% 
  arrange(condition, date1) %>% 
  mutate(value2 = lead(value1))

请注意,arrange()只拨打String s=""; for(int i=1000;i<5000;i++){ s=String.valueOf(i); if(s.contains("1")&&s.contains("2")&&s.contains("4") &&!s.contains("3")&&!s.contains("5")&&!s.contains("6")&&!s.contains("7") &&!s.contains("8")&&!s.contains("9")&&!s.contains("0")){ System.out.println(s); } } 而非拨打两个。