如何根据R中其他两个列的值组合更改列值?

时间:2020-05-26 20:17:52

标签: r dataframe dplyr tidyverse

我有30万个人(身份证)的面板数据。每个ID每年都有1行(2013-2016年)。基于“代码”,确定“名称”的状态(每年)。但是,仍然存在一些错误。如果数据框中的一个ID在特定年份具有特定名称,则我想给每个人提供相同的代码和年份,也要为该名称提供相同的代码和年份。如果没有人在“名称”中有特定代码和年份的名称,则NA就足够了。这有点棘手,因为ID可以在多年内(而不是一年内)使用Codes进行切换。

例如:对于ID#2,2014年的名称应从NA更改为PIZZA,原因是数据框中的另一个ID(此处为#1)的相同ID和Year具有“ PIZZA”。但是,ID#3和ID#4在2016年都保持不变,因为没有人用代码05/1234和2016年在数据框中有名称。

    > str(Poging23)
tibble [16 x 5] (S3: tbl_df/tbl/data.frame)
 $ ID           : num [1:16] 1 1 1 1 2 2 2 2 3 3 ...
 $ Date_of_birth: POSIXct[1:16], format: "2000-05-25" "2000-05-25" "2000-05-25" "2000-05-25" ...
 $ Code         : chr [1:16] "01/1234" "01/1234" "01/1234" "01/1234" ...
 $ Year         : num [1:16] 2013 2014 2015 2016 2013 ...
 $ Name         : chr [1:16] "PIZZA" "PIZZA" "NA" "NA" ...

> dput(Poging23)
structure(list(ID = c(1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 
4, 4, 4), Date_of_birth = structure(c(959212800, 959212800, 959212800, 
959212800, 25315200, 25315200, 25315200, 25315200, 277862400, 
277862400, 277862400, 277862400, 1267574400, 1267574400, 1267574400, 
1267574400), class = c("POSIXct", "POSIXt"), tzone = "UTC"), 
    Code = c("01/1234", "01/1234", "01/1234", "01/1234", "01/1234", 
    "01/1234", "01/1234", "01/1234", "01/1234", "01/1234", "05/1234", 
    "05/1234", "05/1234", "05/1234", "05/1234", "05/1234"), Year = c(2013, 
    2014, 2015, 2016, 2013, 2014, 2015, 2016, 2013, 2014, 2015, 
    2016, 2013, 2014, 2015, 2016), Name = c("PIZZA", "PIZZA", 
    "NA", "NA", "NA", "NA", "PIZZA", "NA", "NA", "PIZZA", "NA", 
    "NA", "PASTA", "PASTA", "PASTA", "NA")), row.names = c(NA, 
-16L), class = c("tbl_df", "tbl", "data.frame"))

不幸的是,这些代码无法正常工作(多年来没有考虑代码的更改):如何根据R中其他ID的单元格值/特征将ID的NA更改为字符值? / p>

编辑:我将NA命名为“ NA”,因为我首先在Excel中进行了预览。

也可以将所有名称更改为1,如果更容易将NA更改为0。

希望有人可以帮助我/给出提示!

谢谢!

2 个答案:

答案 0 :(得分:1)

按代码和年份的功能汇总名称将显示每对因素的名称。对于每对,您可以查看是否至少存在一个名称

aggregate(Name ~ Year + Code, dfx, function(x) {x[x != "NA"]})
  Year    Code         Name
1 2013 01/1234        PIZZA
2 2014 01/1234 PIZZA, PIZZA
3 2015 01/1234        PIZZA
4 2016 01/1234             
5 2013 05/1234        PASTA
6 2014 05/1234        PASTA
7 2015 05/1234        PASTA
8 2016 05/1234             

我将假设每对Year,Code必须始终具有相同的名称(可以在第2行中重复),并且只需要第一个

uu <- aggregate(Name ~ Year + Code, dfx, function(x) {x[x != "NA"][1]})
> uu
  Year    Code  Name
1 2013 01/1234 PIZZA
2 2014 01/1234 PIZZA
3 2015 01/1234 PIZZA
4 2016 01/1234  <NA>
5 2013 05/1234 PASTA
6 2014 05/1234 PASTA
7 2015 05/1234 PASTA
8 2016 05/1234  <NA>

然后为dfx中匹配 uu 的每一行,可以从uu $ Name

中分配相应的名称。
for (i in 1:nrow(uu)) {
  dfx[
     dfx$Name=="NA" 
     & dfx$Code == uu[i, "Code"] 
     & dfx$Year == uu[i, "Year"] , "Name" ] <- uu[i, "Name"]
}
> dfx
   ID Date_of_birth    Code Year  Name
1   1    2000-05-25 01/1234 2013 PIZZA
2   1    2000-05-25 01/1234 2014 PIZZA
3   1    2000-05-25 01/1234 2015 PIZZA
4   1    2000-05-25 01/1234 2016  <NA>
5   2    1970-10-21 01/1234 2013 PIZZA
6   2    1970-10-21 01/1234 2014 PIZZA
7   2    1970-10-21 01/1234 2015 PIZZA
8   2    1970-10-21 01/1234 2016  <NA>
9   3    1978-10-22 01/1234 2013 PIZZA
10  3    1978-10-22 01/1234 2014 PIZZA
11  3    1978-10-22 05/1234 2015 PASTA
12  3    1978-10-22 05/1234 2016  <NA>
13  4    2010-03-03 05/1234 2013 PASTA
14  4    2010-03-03 05/1234 2014 PASTA
15  4    2010-03-03 05/1234 2015 PASTA
16  4    2010-03-03 05/1234 2016  <NA>

答案 1 :(得分:1)

tidyverse宇宙中可能的解决方案可以如下进行。我将过程分为几步,以便更清晰易懂。

首先,我们创建一个查找表,其中包含CodeYear的每种组合,Name中与"NA"

library(tidyverse)

lookup <- Poging23 %>% 
  group_by(Code, Year) %>% 
  group_modify(~unique(.$Name) %>% enframe(name = NULL, value = "Name")) %>% 
  filter(Name != "NA")

# A tibble: 6 x 3
# Groups:   Code, Year [6]
#   Code     Year Name 
#   <chr>   <dbl> <chr>
# 1 01/1234  2013 PIZZA
# 2 01/1234  2014 PIZZA
# 3 01/1234  2015 PIZZA
# 4 05/1234  2013 PASTA
# 5 05/1234  2014 PASTA
# 6 05/1234  2015 PASTA

然后,我们在原始数据集和此查询表之间使用左联接

Poging23 %>% 
  select(-Name) %>% 
  left_join(lookup, by = c("Code", "Year"))

最终输出应符合您的预期

# A tibble: 16 x 5
#       ID Date_of_birth       Code     Year Name 
#    <dbl> <dttm>              <chr>   <dbl> <chr>
#  1     1 2000-05-25 00:00:00 01/1234  2013 PIZZA
#  2     1 2000-05-25 00:00:00 01/1234  2014 PIZZA
#  3     1 2000-05-25 00:00:00 01/1234  2015 PIZZA
#  4     1 2000-05-25 00:00:00 01/1234  2016 NA   
#  5     2 1970-10-21 00:00:00 01/1234  2013 PIZZA
#  6     2 1970-10-21 00:00:00 01/1234  2014 PIZZA
#  7     2 1970-10-21 00:00:00 01/1234  2015 PIZZA
#  8     2 1970-10-21 00:00:00 01/1234  2016 NA   
#  9     3 1978-10-22 00:00:00 01/1234  2013 PIZZA
# 10     3 1978-10-22 00:00:00 01/1234  2014 PIZZA
# 11     3 1978-10-22 00:00:00 05/1234  2015 PASTA
# 12     3 1978-10-22 00:00:00 05/1234  2016 NA   
# 13     4 2010-03-03 00:00:00 05/1234  2013 PASTA
# 14     4 2010-03-03 00:00:00 05/1234  2014 PASTA
# 15     4 2010-03-03 00:00:00 05/1234  2015 PASTA
# 16     4 2010-03-03 00:00:00 05/1234  2016 NA   

如果要避免将过程分成较小的步骤,只需按以下步骤合并代码块

library(tidyverse)

Poging23 %>% 
  select(-Name) %>% 
  left_join(Poging23 %>% 
              group_by(Code, Year) %>% 
              group_modify(~unique(.$Name) %>% enframe(name = NULL, value = "Name")) %>% 
              filter(Name != "NA"),
            by = c("Code", "Year"))