【问题标题】:Reshape data with repeated columns用重复的列重塑数据
【发布时间】:2012-04-08 11:41:21
【问题描述】:

我正在尝试使用 reshape 来重构我的数据集。

这是我的数据的一个子集,它是一个 16 X 198 的数据框。奇数列是 16 年的列表,偶数列的值是不同的国家/地区。

   Algeria.x Algeria.y Argentina.x Argentina.y
1       1985     37.48        1985       27.86
2       1986     36.26        1986       27.52
3       1987     35.04        1987       27.18
4       1988     33.82        1988       26.84
5       1989     32.60        1989       26.50
6       1990        NA        1990       25.50
7       1991        NA        1991       24.50
8       1992        NA        1992       23.50
9       1993        NA        1993       22.50
10      1994        NA        1994       21.50
11      1995        NA        1995       22.12
12      1996        NA        1996       22.74
13      1997        NA        1997       23.36
14      1998        NA        1998       23.98
15      1999        NA        1999       24.60
16      2000        NA        2000          NA

我想重塑数据,使其具有三列。第一个为国家名称,第二个为年份,第三个为值。这将是一个 1584 x 3 的长矩阵。

【问题讨论】:

  • 我能够为一个国家/地区进行重塑,但无法找出可以为每个国家/地区复制的循环或其他代码。如果数据框是'z',我做了 x
  • 根据名称(Algeria.x、Algeria.y 等),上面 data.frame 的子集看起来可能是合并 data.frames 的结果。通过在上一步进行干预,可以避免重新塑造 df。如果你愿意,你会解释导致 df 的步骤吗?或者,如果您感到满意,那么您可以将弗洛德尔的回答标记为已接受。

标签: r reshape


【解决方案1】:

我会使用stack 函数两次,将数据拆分为两个data.frames:一个用于年份,一个用于值:

# split the data into two data.frames
years.df  <- df[, seq(from = 1, to = ncol(df), by = 2)]
values.df <- df[, seq(from = 2, to = ncol(df), by = 2)]

# remove ".x" and ".y" at the end of the country names
names(years.df)  <- sub("\\.x$", "", names(years.df))
names(values.df) <- sub("\\.y$", "", names(values.df))

# stack each data.frame into a two-column data.frame
years.stack  <- stack(years.df)
values.stack <- stack(values.df)

# gather everything into a single data.frame
final.df <- data.frame(country = years.stack$ind,
                       year    = years.stack$value,
                       value   = values.stack$value)
final.df
#      country year value
# 1    Algeria 1985 37.48
# 2    Algeria 1986 36.26
# 3    Algeria 1987 35.04
# 4    Algeria 1988 33.82
# 5    Algeria 1989 32.60
# 6    Algeria 1990    NA
# 7    Algeria 1991    NA
# 8    Algeria 1992    NA
# 9    Algeria 1993    NA
# 10   Algeria 1994    NA
# 11   Algeria 1995    NA
# 12   Algeria 1996    NA
# 13   Algeria 1997    NA
# 14   Algeria 1998    NA
# 15   Algeria 1999    NA
# 16   Algeria 2000    NA
# 17 Argentina 1985 27.86
# 18 Argentina 1986 27.52
# 19 Argentina 1987 27.18
# 20 Argentina 1988 26.84
# 21 Argentina 1989 26.50
# 22 Argentina 1990 25.50
# 23 Argentina 1991 24.50
# 24 Argentina 1992 23.50
# 25 Argentina 1993 22.50
# 26 Argentina 1994 21.50
# 27 Argentina 1995 22.12
# 28 Argentina 1996 22.74
# 29 Argentina 1997 23.36
# 30 Argentina 1998 23.98
# 31 Argentina 1999 24.60
# 32 Argentina 2000    NA

【讨论】:

    【解决方案2】:

    对于这么小的数据框,我想我只需将原始向量分开即可:

    #read in your data
    dat <- read.table(text="   Algeria.x Algeria.y Argentina.x Argentina.y
    1       1985     37.48        1985       27.86
    2       1986     36.26        1986       27.52
    3       1987     35.04        1987       27.18
    4       1988     33.82        1988       26.84
    5       1989     32.60        1989       26.50
    6       1990        NA        1990       25.50
    7       1991        NA        1991       24.50
    8       1992        NA        1992       23.50
    9       1993        NA        1993       22.50
    10      1994        NA        1994       21.50
    11      1995        NA        1995       22.12
    12      1996        NA        1996       22.74
    13      1997        NA        1997       23.36
    14      1998        NA        1998       23.98
    15      1999        NA        1999       24.60
    16      2000        NA        2000          NA")
    

    解决办法:

    dat2 <- data.frame(  #tear apart original vectors & piece 'em together
        country_name = rep(c("Algeria", "Argentina"), each = nrow(dat)),
        year = unlist(dat[, c(1, 3)]), 
        value = unlist(dat[, c(2, 4)])
    )
    
    rownames(dat2) <- 1:nrow(dat2) #give proper row names
    dat2
    

    【讨论】:

    • 我相信这是一个部分数据集,因此使用此解决方案可能有点麻烦,必须重新输入所有国家/地区名称。
    • 它是 16 x 198。取决于堆叠的内容和需要重复的 id 变量dataframe[rep(seq_len(nrow(dataframe)), repeats), ] 也可以派上用场。我同意输入太多名称,gsub 可能会派上用场,但如果您有多个名称重复,那么可能需要输入 8 个名称。
    • 正确,只是16是原始数据集中的行数。我假设有 99 个国家/地区。
    【解决方案3】:

    假设您的数据集名为“df”:原始答案(使用“reshape”包):

    library(reshape)
    # make a new column called year, and select only even columns
    df = data.frame(year=1985:2000, 
                    df[, seq(from=2, to=length(names(df)), by=2)])
    # optional--for removing ".y" from country name
    names(df) = sub("\\.y$", "", names(df))
    # "melt" your dataset
    m.df2 = melt(df, id=1)
    

    更新:更精简的方法

    您可以利用所有国家/地区具有相同年份值的事实,从而使任何“.x”列成为meltdata.frame 的潜在id.var

    仍然需要进行一些清理工作。

    library(reshape2)
    names(df) <- gsub(".y", "", names(df))
    df_long <- setNames(melt(df[, c("Algeria.x", grep(".x", names(df), 
                                                      invert=TRUE, value=TRUE))],
                             id.vars="Algeria.x"), c("Year", "Country", "Value"))
    list(head(df_long), tail(df_long))
    # [[1]]
    #   Year Country Value
    # 1 1985 Algeria 37.48
    # 2 1986 Algeria 36.26
    # 3 1987 Algeria 35.04
    # 4 1988 Algeria 33.82
    # 5 1989 Algeria 32.60
    # 6 1990 Algeria    NA
    # 
    # [[2]]
    #    Year   Country Value
    # 27 1995 Argentina 22.12
    # 28 1996 Argentina 22.74
    # 29 1997 Argentina 23.36
    # 30 1998 Argentina 23.98
    # 31 1999 Argentina 24.60
    # 32 2000 Argentina    NA
    

    【讨论】:

      【解决方案4】:

      一个使用基本函数reshape的衬垫。

      reshape(dat, varying = 1:4, direction = 'long')
      

      【讨论】:

        猜你喜欢
        • 2018-07-15
        • 2017-04-05
        • 2012-10-01
        • 2014-09-20
        • 2019-05-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多