【问题标题】:Reorder levels of factor names in data frame重新排序数据框中因子名称的级别
【发布时间】:2016-05-18 10:22:57
【问题描述】:

我有一个DF,只有一列:DF$A。这是我需要以特定方式重新排序的名称的一个因素:

l
pheno
l.ldl.a
m.ldl.b
s.ldl.c
x.vldl.b
l.vldl.c
m.vldl.d
s.vldl.f
xs.vldl.h
xxl.vldl.a
xl.hdl.a
l.hdl.b
m.hdl.c
s.hdl.d

我尝试根据两个重新排序的DF$A 创建column 2

reorderLevels <- c(XXL.VLDL,XL.VLDL,L.VLDL,M.VLDL,S.VLDL,XS.VLDL, 
                   IDL,L.LDL,M.LDL,S.LDL,XL.HDL,L.HDL,M.HDL,S.HDL)

不关心名字的最后一部分。

我知道如何根据名称的第一部分(第一个点之前)或名称的第二部分(点之间的部分)重新排序,但我不知道如何根据名称的两个部分进行排列。

到目前为止,我可以使用以下命令对其重新排序,但仅根据名称的一部分

l1 <- l %>% mutate(m2 = match(sapply(strsplit(l$pheno, "[.]"),
                          function(x) x[1]), reorderLevels)) %>%
            arrange(m2) %>%
            select(-m2)

【问题讨论】:

    标签: r sorting r-factor


    【解决方案1】:

    我不是 100% 确定你在问什么。我认为您想根据以下方案对因子 DF$A 重新排序:

    • 最高优先级:按中间部分排列,顺序如下:

      middle.ordering = c('vldl', 'idl', 'ldl', 'hdl')
      
    • 第二优先:按以下顺序排列第一部分(我添加了一个“x”,即使它不在您的reoderLines 中,因为您在 DF$A 中有一个“x”):

      first.ordering = c('xxl', 'xl', 'l', 'm', 's', 'x', 'xs')
      
    • 你不关心最后一部分的顺序,但我只知道如果我们指定一个,我就知道如何轻松解决这个问题,所以我选择了我在最后一部分中看到的字母的任意顺序:

      last.ordering = c('a', 'b', 'c', 'd', 'f', 'h')
      

    至于你的最终输出,我不知道你想要什么。我能想到你可能想要的 4 件事:

    • DF$A 按照你写它的确切顺序,但是按照你想要的顺序添加新的级别。如果您绘制这些数据的图,这将很有用,因为这些图将根据因子水平进行排列。这也意味着如果您在数据框中有其他列,您可以保持所有行的配对相同。看起来像这样:

       [1] l.ldl.a    m.ldl.b    s.ldl.c    x.vldl.b   l.vldl.c   m.vldl.d   s.vldl.f   xs.vldl.h  xxl.vldl.a xl.hdl.a   l.hdl.b    m.hdl.c   
      [13] s.hdl.d   
      Levels: xxl.vldl.a l.vldl.c m.vldl.d s.vldl.f x.vldl.b xs.vldl.h l.ldl.a m.ldl.b s.ldl.c xl.hdl.a l.hdl.b m.hdl.c s.hdl.d
      
    • DF$A 以新的顺序排列,但按字母顺序排列的级别与以前相同(例如,级别 1 对应于 l.hdl.b,因为这是 DF$A 按字母顺序排列的第一个元素)。看起来像这样:

       [1] xxl.vldl.a l.vldl.c   m.vldl.d   s.vldl.f   x.vldl.b   xs.vldl.h  l.ldl.a    m.ldl.b    s.ldl.c    xl.hdl.a   l.hdl.b    m.hdl.c   
      [13] s.hdl.d   
      Levels: l.hdl.b l.ldl.a l.vldl.c m.hdl.c m.ldl.b m.vldl.d s.hdl.d s.ldl.c s.vldl.f xl.hdl.a xs.vldl.h x.vldl.b xxl.vldl.a
      
    • DF$A 以新顺序,新级别。看起来像这样:

       [1] xxl.vldl.a l.vldl.c   m.vldl.d   s.vldl.f   x.vldl.b   xs.vldl.h  l.ldl.a    m.ldl.b    s.ldl.c    xl.hdl.a   l.hdl.b    m.hdl.c   
      [13] s.hdl.d   
      Levels: xxl.vldl.a l.vldl.c m.vldl.d s.vldl.f x.vldl.b xs.vldl.h l.ldl.a m.ldl.b s.ldl.c xl.hdl.a l.hdl.b m.hdl.c s.hdl.d
      
    • 您可能还希望在 DF$A 中实际实现的因子有更多可能的水平,例如如果您稍后要添加更多数据。如果是这种情况,那么您的输出将如下所示,其中包含三个部分的所有可能排序:

       [1] l.ldl.a    m.ldl.b    s.ldl.c    x.vldl.b   l.vldl.c   m.vldl.d   s.vldl.f   xs.vldl.h  xxl.vldl.a xl.hdl.a   l.hdl.b    m.hdl.c   
      [13] s.hdl.d   
      168 Levels: xxl.vldl.a xxl.vldl.b xxl.vldl.c xxl.vldl.d xxl.vldl.f xxl.vldl.h xl.vldl.a xl.vldl.b xl.vldl.c xl.vldl.d xl.vldl.f ... xs.hdl.h
      

    如果其中一件事情是你想要的,那么这里有一种方法来做这些事情:

    DF = data.frame(A=factor(c(
      'l.ldl.a',
      'm.ldl.b',
      's.ldl.c',
      'x.vldl.b',
      'l.vldl.c',
      'm.vldl.d',
      's.vldl.f',
      'xs.vldl.h',
      'xxl.vldl.a',
      'xl.hdl.a',
      'l.hdl.b',
      'm.hdl.c',
      's.hdl.d')))
    
    first.ordering = c('xxl', 'xl', 'l', 'm', 's', 'x', 'xs')
    middle.ordering = c('vldl', 'idl', 'ldl', 'hdl')
    last.ordering = c('a', 'b', 'c', 'd', 'f', 'h')
    
    # make a big cartesion product of the orderings,
    # making sure that the top-priority orderings are mentioned *last*
    # in expand.gird
    complete.ordering = with(
      expand.grid(last.ordering, first.ordering, middle.ordering),
      paste(Var2, Var3, Var1, sep='.'))
    new.levels = complete.ordering[complete.ordering %in% DF$A]
    
    A.with.new.levels.but.same.order = factor(DF$A, levels=new.levels)
    A.with.new.order.but.same.levels = DF$A[order(as.numeric(A.with.new.levels.but.same.order))]
    A.with.new.order.and.levels = factor(A.with.new.order.but.same.levels, levels=new.levels)
    A.with.same.order.and.more.levels = factor(DF$A, levels=complete.ordering)
    

    另外,如果您的原始数据框有更多列,例如,如果它看起来像这样:

                A another.column
    1     l.ldl.a              1
    2     m.ldl.b              2
    3     s.ldl.c              3
    4    x.vldl.b              4
    5    l.vldl.c              5
    6    m.vldl.d              6
    7    s.vldl.f              7
    8   xs.vldl.h              8
    9  xxl.vldl.a              9
    10   xl.hdl.a             10
    11    l.hdl.b             11
    12    m.hdl.c             12
    13    s.hdl.d             13
    

    并且您想将所有行的顺序重新排列在一起,保留每行元素之间的关联,那么您可以执行以下操作:

    A.with.new.levels.but.same.order = factor(DF$A, levels=new.levels)
    DF.with.new.order = DF[order(as.numeric(A.with.new.levels.but.same.order)),]
    

    这将为您提供以下数据框:

                A another.column
    9  xxl.vldl.a              9
    5    l.vldl.c              5
    6    m.vldl.d              6
    7    s.vldl.f              7
    4    x.vldl.b              4
    8   xs.vldl.h              8
    1     l.ldl.a              1
    2     m.ldl.b              2
    3     s.ldl.c              3
    10   xl.hdl.a             10
    11    l.hdl.b             11
    12    m.hdl.c             12
    13    s.hdl.d             13
    

    【讨论】:

    • 我能再问你一个问题吗。抱歉打扰了。如果你能回答,如果我有一个超过 1 列的 DF,并且我使用你提供的代码来重新排列该列,那么我如何相应地重新排列行。抱歉打扰了。
    • 仍然不确定我是否理解。你的意思是你想重新排序整个数据框?如果这就是你想要的,那么这样的东西应该可以工作:DF.with.new.order = DF[order(as.numeric(A.with.new.levels.but.same.order)),](对不起,我不知道如何格式化 cmets!!!)
    • 我编辑了答案的结尾,因为我认为这可能更清楚。如果我误解了这个问题,请随时问更多。
    • 你是天才 :) 非常感谢!
    【解决方案2】:

    我想建议tidyrdplyr 作为替代方案。

    DF %>%
     separate("A", c("first", "middle", "last"), sep="[.]") %>%
     arrange(middle, first) %>%
     unite(A, c(first, middle,last), sep=".") %>%
     mutate(A=as.factor(A))
    

    首先我们将这三个部分分开,排列它们并结合起来。最后,我们按照这个新顺序重做关卡。

    这给了

                A
    1     l.hdl.b
    2     m.hdl.c
    3     s.hdl.d
    4    xl.hdl.a
    5     l.ldl.a
    6     m.ldl.b
    7     s.ldl.c
    8    l.vldl.c
    9    m.vldl.d
    10   s.vldl.f
    11   x.vldl.b
    12  xs.vldl.h
    13 xxl.vldl.a
    

    levels 答案略长,但可能更具可读性。

    【讨论】:

    • 谢谢您,但订单不是我正在寻找的。这是我的错,我没有很好地解释它
    【解决方案3】:

    如果您想重新排序,例如,第二部分然后是第一部分(它们已经先排序,然后是第二部分),请按重要性顺序传递您关心的标签部分 order。可以使用sub拉出碎片:

    levels(DF$A) <- levels(DF$A)[order(sub('.*\\.(.*)\\..*', '\\1', levels(DF$A)), 
                                       sub('\\..*', '', levels(DF$A)))]
    
    levels(DF$A)
    # [1] "l.hdl.b"    "m.hdl.c"    "s.hdl.d"    "xl.hdl.a"   "l.ldl.a"    "m.ldl.b"    "s.ldl.c"   
    # [8] "l.vldl.c"   "m.vldl.d"   "s.vldl.f"   "x.vldl.b"   "xs.vldl.h"  "xxl.vldl.a"
    

    注意hdls 是第一位的,其中的排序按第一部分排序。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-10
      • 1970-01-01
      • 2022-01-07
      相关资源
      最近更新 更多