按ID对数据帧中的一个变量进行排序

时间:2019-03-20 08:53:12

标签: r sorting grouping

我有一个数据框,其中包含许多公司信息,并用id变量分隔。我想对变量之一进行排序,并为每个id重复它。让我们以这个例子为例,

df <- structure(list(id = c(110, 110, 110, 90, 90, 90, 90, 252, 252
), var1 = c(26, 21, 54, 10, 18, 9, 16, 54, 39), var2 = c(234, 
12, 43, 32, 21, 19, 16, 34, 44)), .Names = c("id", "var1", "var2"
), row.names = c(NA, -9L), class = "data.frame")

看起来像这样

df
   id var1 var2
1 110   26  234
2 110   21   12
3 110   54   43
4  90   10   32
5  90   18   21
6  90    9   19
7  90   16   16
8 252   54   34
9 252   39   44

现在,我想通过向量var1根据id对数据帧进行排序。我能想到的最简单的解决方案是使用apply函数,

> apply(df, 2, sort)
       id var1 var2
 [1,]  90    9   12
 [2,]  90   10   16
 [3,]  90   16   19
 [4,]  90   18   21
 [5,] 110   21   32
 [6,] 110   26   34
 [7,] 110   39   43
 [8,] 252   54   44
 [9,] 252   54  234

但是,这不是我想要的输出。正确的输出应为

   id var1 var2
1 110   21   12
2 110   26  234
3 110   54   43
4  90    9   19
5  90   10   32
6  90   16   16
7  90   18   21
8 252   39   44
9 252   54   34

id分组并按var1进行排序,并且保持原始的id列顺序。

有人知道如何排序吗?

5 个答案:

答案 0 :(得分:6)

另一个使用ordermatch的基本R选项

df[with(df, order(match(id, unique(id)), var1, var2)), ]
#   id var1 var2
#2 110   21   12
#1 110   26  234
#3 110   54   43
#6  90    9   19
#4  90   10   32
#7  90   16   16
#5  90   18   21
#9 252   39   44
#8 252   54   34

答案 1 :(得分:6)

注意。如Moody_Mudskipper所述,无需使用tidyverse,也可以使用基础R轻松完成:

df[order(ordered(df$id, unique(df$id)), df$var1), ]

没有任何tidyverse变量的单线temp解决方案:

library(tidyverse)
df %>% arrange(ordered(id, unique(id)), var1)
#    id var1 var2
# 1 110   26  234
# 2 110   21   12
# 3 110   54   43
# 4  90   10   32
# 5  90   18   21
# 6  90    9   19
# 7  90   16   16
# 8 252   54   34
# 9 252   39   44

说明apply(df, 2, sort)不起作用的原因

您试图做的是对每一列进行独立排序。 apply在指定的维度上运行(在这种情况下,2与列相对应)并应用函数(在这种情况下,sort)。

apply试图进一步简化结果,在这种情况下,简化为矩阵。因此,您将获得一个矩阵(不是一个data.frame),其中每个列均独立排序。例如,来自apply调用的这一行:

# [1,]  90    9   12

甚至在原始data.frame中也不存在。

答案 2 :(得分:3)

我们可以将id转换为因数,以便在保留原始顺序的同时进行拆分。然后,我们可以遍历列表和顺序,然后再次rbind,即

df$id <- factor(df$id, levels = unique(df$id))
do.call(rbind, lapply(split(df, df$id), function(i)i[order(i$var1),]))

#       id var1 var2
#110.2 110   21   12
#110.1 110   26  234
#110.3 110   54   43
#90.6   90    9   19
#90.4   90   10   32
#90.7   90   16   16
#90.5   90   18   21
#252.9 252   39   44
#252.8 252   54   34

注意:您可以通过rownames(new_df) <- NULL

重置行名。

答案 3 :(得分:3)

在基础 public static void listItems() throws Exception { ItemView view = new ItemView(100); FolderView view1 = new FolderView(100); Folder folder = Folder.bind(service, WellKnownFolderName.MsgFolderRoot); SearchFilter filterFolder = new SearchFilter.IsEqualTo(FolderSchema.DisplayName,"Posteingang"); FindItemsResults<Item> findInbox = service.findItems(new FolderId(uniqueId),view); FindFoldersResults findFolderResults = folder.findFolders(filterFolder, view1); service.loadPropertiesForFolder(folder, PropertySet.FirstClassProperties); service.loadPropertiesForItems(findInbox, PropertySet.FirstClassProperties); for (Folder f : findFolderResults.getFolders()) { System.out.println("Displayname=====" + f.getDisplayName()); for (Item item : findInbox.getItems()) { System.out.println("sub==========" + item.getSubject()); System.out.println(item.getClass()); counter++; } } System.out.println(counter); } 中,我们可以使用R

split<-

或@Markus建议:

split(df,df$id) <- lapply(split(df,df$id), function(x) x[order(x$var1),] )

在两种情况下的输出:

split(df, df$id) <- by(df, df$id, function(x) x[order(x$var1),])

答案 4 :(得分:2)

通过下面的tidyverse管道,将复制问题的输出。

library(tidyverse)

df %>%
  mutate(tmp = cumsum(c(0, diff(id) != 0))) %>%
  group_by(id) %>%
  arrange(tmp, var1) %>%
  select(-tmp)
## A tibble: 9 x 3
## Groups:   id [3]
#     id  var1  var2
#  <dbl> <dbl> <dbl>
#1   110    21    12
#2   110    26   234
#3   110    54    43
#4    90     9    19
#5    90    10    32
#6    90    16    16
#7    90    18    21
#8   252    39    44
#9   252    54    34