重新排序数据框中因子名称的级别

问题描述 投票:1回答:3

我有一个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

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

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
3个回答
4
投票

我不是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

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答案略长,但也许更具可读性。


1
投票

如果你想重新排序第二部分,然后是第一部分(它们已经先订购,然后是第二部分),请按照重要性的顺序将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是第一个,排序在第一部分排序。

© www.soinside.com 2019 - 2024. All rights reserved.