【问题标题】:R: Where a value in two data frames is the same, apply a set of condition on one to determine its classificationR:如果两个数据帧中的值相同,则对一个数据帧应用一组条件以确定其分类
【发布时间】:2015-12-01 02:31:49
【问题描述】:

我有两组数据。我希望根据另一个(年份和三个断点)中包含的条件应用第一组(按年收入)的分类(低、中低、中高、高)。以下是来自这些数据集的样本 - 真实数据集要大得多,而且长度不同。

收入

    Country Year    GNI.caput
Argentina   2000    7470
Argentina   2001    7000
Argentina   2002    4050
Argentina   2003    3670
Argentina   2004    3810
Denmark 2000    32660
Denmark 2001    31440
Denmark 2002    30870
Denmark 2003    34850
Denmark 2004    42760
Kenya   2000    420
Kenya   2001    400
Kenya   2002    390
Kenya   2003    410
Kenya   2004    460
Philippines 2000    1230
Philippines 2001    1230
Philippines 2002    1190
Philippines 2003    1270
Philippines 2004    1400

休息

Year    Break.1 Break.2 Break.3
2004    825 3225    10065
2003    765 3035    9385
2002    735 2935    9075
2001    745 2975    9205
2000    755 2995    9265

我尝试了以下几组循环,但都没有完成,每个都产生了几个错误。

尝试 1

for(i in seq_along(gni.data)){
    while(gni.data$Year == break.pts$Year) {
        if(gni.data$GNI.caput <= break.pts$Break.1) {
            gni.data$Indicator <- "Low"
        } else if(gni.data$GNI.caput <= break.pts$Break.2) {
            gni.data$Indicator <- "Mid.Low"
        } else if(gni.data$GNI.caput <= break.pts$Break.3) {
            gni.data$Indicator <- "Mid.Up"
        } else if(gni.data$GNI.caput > break.pts$Break.3) {
            gni.data$Indicator <- "High"
        } else gni.data$Indicator <- "NA"
    }
}

警告信息: 1:在 gni.data$Year == break.pts$Year 中: 较长的对象长度不是较短对象长度的倍数 2: 在 while (gni.data$Year == break.pts$Year) { : 条件的长度 > 1 并且只使用第一个元素 ...

尝试 2

for(i in seq_along(gni.data)){
    while(gni.data$Year == break.pts$Year) {
        ifelse(gni.data$GNI.caput <= break.pts$Break.1, gni.data$Indicator <- "Low", 
                ifelse(gni.data$GNI.caput <= break.pts$Break.2, gni.data$Indicator <- "Mid.Lo",
                       ifelse(gni.data$GNI.caput <= break.pts$Break.3, gni.data$Indicator <- "Mid.Up",
                              ifelse(gni.data$GNI.caput > break.pts$Break.3, gni.data$Indicator <- "High",
                                     gni.data$Indicator <- "NA"))))
    }
}

警告消息与尝试 1 相同。

我哪里错了?谢谢!

【问题讨论】:

  • 您的警告消息暗示您在 break.pts$Year 中有多个元素。如果这是故意的,那么您可以尝试将您的“==”替换为“%in%”,这将接受一个向量。
  • 如果你合并两个数据集,这可能会更容易做到,使用国家年份一个作为x,一个有削减的作为y,并设置all.x=TRUE。然后,您可以使用对 ifelse() 的一对嵌套调用编写更简单的代码,而无需使用 for 循环。

标签: r if-statement for-loop while-loop


【解决方案1】:

您可以通过在调用with() 中临时合并两个数据框,然后使用嵌套的ifelse() 调用来创建新变量,如下所示:

# Toy data to test
df <- data.frame(country=rep(c("A", "B", "C"), each=3), year=rep(seq(2000,2002), 3), gdp = rnorm(9, 5000, 1000), stringsAsFactors=FALSE)
cuts <- data.frame(year = seq(2000,2002), break.1=c(4000,4500,4000), break.2=c(5000,5500,5000), break.3=c(6000,6500,6000))

# Create new variable using merge of two data sets
df$class <- with(merge(df, cuts, all.x=TRUE),
    ifelse(gdp < break.1, "lo", ifelse(gdp >= break.1 & gdp < break.2, "mid.lo",
        ifelse(gdp >= break.2 & gdp < break.3, "mid.hi", ifelse(gdp >= break.3, "hi", NA)))))

# Result
> newdf
  year country      gdp break.1 break.2 break.3  class
1 2000       A 5510.243    4000    5000    6000 mid.hi
2 2000       C 6404.494    4000    5000    6000     hi
3 2000       B 6125.383    4000    5000    6000     hi
4 2001       A 4899.577    4500    5500    6500 mid.lo
5 2001       B 4678.249    4500    5500    6500 mid.lo
6 2001       C 6026.577    4500    5500    6500 mid.hi
7 2002       B 6350.749    4000    5000    6000     hi
8 2002       A 7225.358    4000    5000    6000     hi
9 2002       C 5469.354    4000    5000    6000 mid.hi

您还可以使用dplyr 及其管道运算符一次性合并、重新编码、排序和剪切多余的列:

library(dplyr)
df <- left_join(df, cuts) %>%
    mutate(class = ifelse(gdp < break.1, "lo", ifelse(gdp >= break.1 & gdp < break.2, "mid.lo",
    ifelse(gdp >= break.2 & gdp < break.3, "mid.hi", ifelse(gdp >= break.3, "hi", NA))))) %>%
    arrange(country, year) %>%
    select(-break.1, -break.2, -break.3)

# Result
>df
  country year      gdp  class
1       A 2000 5510.243 mid.hi
2       A 2001 4899.577 mid.lo
3       A 2002 7225.358     hi
4       B 2000 6125.383     hi
5       B 2001 4678.249 mid.lo
6       B 2002 6350.749     hi
7       C 2000 6404.494     hi
8       C 2001 6026.577 mid.hi
9       C 2002 5469.354 mid.hi

【讨论】:

  • 谢谢!比我混乱、过于复杂的尝试要优雅得多。
  • 很高兴它成功了。我修改了基础 R 版本,将合并嵌入到创建新变量的行中,这样您就可以一次性完成,而无需创建新对象。
猜你喜欢
  • 2017-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-22
  • 1970-01-01
  • 1970-01-01
  • 2021-10-18
相关资源
最近更新 更多