代码之家  ›  专栏  ›  技术社区  ›  mropa

将data.frame从宽格式改为长格式

  •  110
  • mropa  · 技术社区  · 15 年前

    我很难把我的 data.frame 从宽桌子到长桌子。 目前看来:

    Code Country        1950    1951    1952    1953    1954
    AFG  Afghanistan    20,249  21,352  22,532  23,557  24,555
    ALB  Albania        8,097   8,986   10,058  11,123  12,246
    

    现在我想改变这个 数据帧 长成 数据帧 . 像这样的:

    Code Country        Year    Value
    AFG  Afghanistan    1950    20,249
    AFG  Afghanistan    1951    21,352
    AFG  Afghanistan    1952    22,532
    AFG  Afghanistan    1953    23,557
    AFG  Afghanistan    1954    24,555
    ALB  Albania        1950    8,097
    ALB  Albania        1951    8,986
    ALB  Albania        1952    10,058
    ALB  Albania        1953    11,123
    ALB  Albania        1954    12,246
    

    我已经用 melt() 以及 reshape() 功能 因为有些人提出了类似的问题。 然而,到目前为止,我只得到混乱的结果。

    如果可能的话,我想用 RESHAPE() 功能自 它看起来有点好处理。

    5 回复  |  直到 6 年前
        1
  •  68
  •   Jaap    7 年前

    reshape() 需要一段时间来适应,就像 melt / cast . 这里有一个带整形的解决方案,假设您的数据帧是 d :

    reshape(d, direction = "long", varying = list(names(d)[3:7]), v.names = "Value", 
            idvar = c("Code","Country"), timevar = "Year", times = 1950:1954)
    
        2
  •  101
  •   Jaap    6 年前

    三种替代解决方案:

    1:与 reshape2

    library(reshape2)
    long <- melt(wide, id.vars = c("Code", "Country"))
    

    给:

       Code     Country variable  value
    1   AFG Afghanistan     1950 20,249
    2   ALB     Albania     1950  8,097
    3   AFG Afghanistan     1951 21,352
    4   ALB     Albania     1951  8,986
    5   AFG Afghanistan     1952 22,532
    6   ALB     Albania     1952 10,058
    7   AFG Afghanistan     1953 23,557
    8   ALB     Albania     1953 11,123
    9   AFG Afghanistan     1954 24,555
    10  ALB     Albania     1954 12,246
    

    给出相同结果的一些替代符号:

    # you can also define the id-variables by column number
    melt(wide, id.vars = 1:2)
    
    # as an alternative you can also specify the measure-variables
    # all other variables will then be used as id-variables
    melt(wide, measure.vars = 3:7)
    melt(wide, measure.vars = as.character(1950:1954))
    

    2:与 data.table

    你也可以用同样的 melt 功能与 RESHAPE2 包(这是一个扩展和改进的实现)。 熔化 数据表 还有更多的参数 熔化 -功能来自 RESHAPE2 . 例如,还可以指定变量列的名称:

    library(data.table)
    long <- melt(setDT(wide), id.vars = c("Code","Country"), variable.name = "year")
    

    一些替代符号:

    melt(setDT(wide), id.vars = 1:2, variable.name = "year")
    melt(setDT(wide), measure.vars = 3:7, variable.name = "year")
    melt(setDT(wide), measure.vars = as.character(1950:1954), variable.name = "year")
    

    3:与 tidyr

    library(tidyr)
    long <- wide %>% gather(year, value, -c(Code, Country))
    

    一些替代符号:

    wide %>% gather(year, value, -Code, -Country)
    wide %>% gather(year, value, -1:-2)
    wide %>% gather(year, value, -(1:2))
    wide %>% gather(year, value, -1, -2)
    wide %>% gather(year, value, 3:7)
    wide %>% gather(year, value, `1950`:`1954`)
    

    如果你想排除 NA 值,可以添加 na.rm = TRUE 熔化 以及 gather 功能。


    数据的另一个问题是r将这些值作为字符值读取(结果是 , 在数字中)。你可以用 gsub as.numeric :

    long$value <- as.numeric(gsub(",", "", long$value))
    

    或直接与 数据表 dplyr :

    # data.table
    long <- melt(setDT(wide),
                 id.vars = c("Code","Country"),
                 variable.name = "year")[, value := as.numeric(gsub(",", "", value))]
    
    # tidyr and dplyr
    long <- wide %>% gather(year, value, -c(Code,Country)) %>% 
      mutate(value = as.numeric(gsub(",", "", value)))
    

    数据:

    wide <- read.table(text="Code Country        1950    1951    1952    1953    1954
    AFG  Afghanistan    20,249  21,352  22,532  23,557  24,555
    ALB  Albania        8,097   8,986   10,058  11,123  12,246", header=TRUE, check.names=FALSE)
    
        3
  •  29
  •   zx8754    7 年前

    使用 重塑 包裹:

    #data
    x <- read.table(textConnection(
    "Code Country        1950    1951    1952    1953    1954
    AFG  Afghanistan    20,249  21,352  22,532  23,557  24,555
    ALB  Albania        8,097   8,986   10,058  11,123  12,246"), header=TRUE)
    
    library(reshape)
    
    x2 <- melt(x, id = c("Code", "Country"), variable_name = "Year")
    x2[,"Year"] <- as.numeric(gsub("X", "" , x2[,"Year"]))
    
        4
  •  8
  •   A5C1D2H2I1M1N2O1R2T1    7 年前

    因为这个答案被标记为 ,我觉得分享另一个R基地的替代方案会很有用: stack .

    不过,请注意 堆栈 不适用于 factor S——只有在 is.vector TRUE ,并从 IS.矢量 ,我们发现:

    IS.矢量 收益率 真的 如果x是没有属性的指定模式的向量 除了名字 . 它返回 FALSE 否则。

    我在用样本数据 from @Jaap's answer ,其中“年份”列中的值为 因素 S.

    这里是 堆栈 途径:

    cbind(wide[1:2], stack(lapply(wide[-c(1, 2)], as.character)))
    ##    Code     Country values  ind
    ## 1   AFG Afghanistan 20,249 1950
    ## 2   ALB     Albania  8,097 1950
    ## 3   AFG Afghanistan 21,352 1951
    ## 4   ALB     Albania  8,986 1951
    ## 5   AFG Afghanistan 22,532 1952
    ## 6   ALB     Albania 10,058 1952
    ## 7   AFG Afghanistan 23,557 1953
    ## 8   ALB     Albania 11,123 1953
    ## 9   AFG Afghanistan 24,555 1954
    ## 10  ALB     Albania 12,246 1954
    
        5
  •  7
  •   Mark Peterson    8 年前

    下面是另一个使用 gather tidyr . 您可以选择列 聚集 或者单独删除它们(就像我在这里所做的),或者明确地包含您想要的年份。

    注意,要处理逗号(如果 check.names = FALSE 未设置),我也在使用 dplyr 的变异 parse_number readr 将文本值转换回数字。这些都是 tidyverse 所以可以和 library(tidyverse)

    wide %>%
      gather(Year, Value, -Code, -Country) %>%
      mutate(Year = parse_number(Year)
             , Value = parse_number(Value))
    

    返回:

       Code     Country Year Value
    1   AFG Afghanistan 1950 20249
    2   ALB     Albania 1950  8097
    3   AFG Afghanistan 1951 21352
    4   ALB     Albania 1951  8986
    5   AFG Afghanistan 1952 22532
    6   ALB     Albania 1952 10058
    7   AFG Afghanistan 1953 23557
    8   ALB     Albania 1953 11123
    9   AFG Afghanistan 1954 24555
    10  ALB     Albania 1954 12246