将面板数据转换为R中的Long

时间:2018-07-10 14:25:39

标签: r format long-integer

我当前的数据是1920年至2018年之间的导弹。目标是衡量一个国家从1920年至2018年每年部署不同类型导弹的能力。出现的问题是该数据在每个国家和地区都有多次观测经常每年。这就产生了问题,因为例如,如果一个国家在1970年采用了空对空导弹并进口,然后在1980年研制了空对空和空对地导弹并在国内生产,那么这种变化就必须得到体现。目标是每个国家/地区每年都有唯一的行/观测。还应该指出的是,假设该国是否可以在1970年生产空运,直到2018年。 当前:

YearAcquired CountryCode CountryName Domestic AirtoAir
     2014         670    Saudi Arabia    0        1
     2017         670    Saudi Arabia    1        1
     2016          2    United States    1        1

所需:

YearAcquired CountryCode CountryName Domestic AirtoAir
     2014         670    Saudi Arabia    0        1
     2015         670    Saudi Arabia    0        1
     2016         670    Saudi Arabia    0        1
     2017         670    Saudi Arabia    1        1
     2018         670    Saudi Arabia    1        1
     2016          2    United States    0        1
     2017          2    United States    0        1
     2018          2    United States    0        1

注意:条目很多,因此我希望每个国家(从1920年到2018年)的值都为零。那不是必须的,但是会很大!

3 个答案:

答案 0 :(得分:0)

您可以使用可用的国家/地区名称和代码创建新的数据框,然后对现有数据执行左连接。这将为您提供1920-2018年的每个国家/地区和代码,将NA保留在您没有可用数据的地方,但是您可以根据想要的数据结构轻松替换它们。

# df is your initial dataframe 
countries <- df$CountryName
codes <- df

new_df <- data.frame(YearAcquired = seq(1920, 2018, 1),
           CountryName = df$CountryName
           CountryCode = df$CountryCode)
new_df <- left_join(new_df, df)

答案 1 :(得分:0)

您可以通过以下几个步骤进行操作:

  1. 创建所有年份和国家/地区的组合(SQL中的CROSS JOIN)
  2. 将这些组合与可用数据结合起来
  3. 使用zoo::na.locf()之类的函数将NA值替换为每个国家/地区的最新已知数值。

第一步很常见:

df <- read.table(text = 'YearAcquired CountryCode CountryName Domestic AirtoAir
     2014         670    "Saudi Arabia"    0        1
     2017         670    "Saudi Arabia"    1        1
     2016          2    "United States"    1        1', header = TRUE, stringsAsFactors = FALSE)

combinations <- merge(data.frame(YearAcquired = seq(1920, 2018, 1)),
                      unique(df[,2:3]), by = NULL)

对于第2步和第3步,此处使用dplyr

library(dplyr)
library(zoo)

df <- left_join(combinations, df) %>%
      group_by(CountryCode) %>%
      mutate(Domestic = na.locf(Domestic, na.rm = FALSE),
             AirtoAir = na.locf(AirtoAir, na.rm = FALSE))

还有一种使用data.table的解决方案:

library(data.table)
library(zoo)

setDT(df)
setDT(combinations)

df <- df[combinations, on = c("YearAcquired", "CountryCode", "CountryName")]
df <- df[, na.locf(.SD, na.rm = FALSE), by = "CountryCode"]

答案 2 :(得分:0)

使用)...

如果您只需要填写每个国家/地区的内部年份...

df <- read.table(header = TRUE, as.is = TRUE, text = "
YearAcquired  countrycode   CountryName    Domestic  AirtoAir
2014          670           'Saudi Arabia'    0         1
2017          670           'Saudi Arabia'    1         1
2016          2             'United States'   1         1
")

library(dplyr)
library(tidyr)

df %>% 
  group_by(countrycode) %>% 
  complete(YearAcquired = full_seq(YearAcquired, 1), countrycode, CountryName) %>% 
  arrange(countrycode, YearAcquired) %>% 
  fill(Domestic, AirtoAir)

#> # A tibble: 5 x 5
#> # Groups:   countrycode [2]
#>   YearAcquired countrycode CountryName   Domestic AirtoAir
#>          <dbl>       <int> <chr>            <int>    <int>
#> 1         2016           2 United States        1        1
#> 2         2014         670 Saudi Arabia         0        1
#> 3         2015         670 Saudi Arabia         0        1
#> 4         2016         670 Saudi Arabia         0        1
#> 5         2017         670 Saudi Arabia         1        1

如果要将每个国家/地区扩展到数据集中找到的所有年份...

df <- read.table(header = TRUE, as.is = TRUE, text = "
YearAcquired  countrycode   CountryName    Domestic  AirtoAir
2014          670           'Saudi Arabia'    0         1
2017          670           'Saudi Arabia'    1         1
2016          2             'United States'   1         1
")

library(dplyr)
library(tidyr)

df %>% 
  complete(YearAcquired = full_seq(YearAcquired, 1), 
           nesting(countrycode, CountryName)) %>% 
  group_by(countrycode) %>% 
  arrange(countrycode, YearAcquired) %>% 
  fill(Domestic, AirtoAir) %>% 
  mutate_at(vars(Domestic, AirtoAir), funs(if_else(is.na(.), 0L, .)))

#> # A tibble: 8 x 5
#> # Groups:   countrycode [2]
#>   YearAcquired countrycode CountryName   Domestic AirtoAir
#>          <dbl>       <int> <chr>            <int>    <int>
#> 1         2014           2 United States        0        0
#> 2         2015           2 United States        0        0
#> 3         2016           2 United States        1        1
#> 4         2017           2 United States        1        1
#> 5         2014         670 Saudi Arabia         0        1
#> 6         2015         670 Saudi Arabia         0        1
#> 7         2016         670 Saudi Arabia         0        1
#> 8         2017         670 Saudi Arabia         1        1