在 R 中对多列数据框进行排序和子集化?

PM.*_*PM. 0 r subset dataframe

我想按某些列和子集订购多列数据框,但使用的命令不起作用

print(df[order(df$x) & df$x < 5,])
Run Code Online (Sandbox Code Playgroud)

这不会对结果进行排序。

为了调试它,我生成了一个带有 1 列的测试数据框,但是这种“简化”产生了意想不到的效果

df <- data.frame(x = sample(1:50))

print(df[order(df$x) & df$x < 5,])
Run Code Online (Sandbox Code Playgroud)

这不会对结果进行排序,所以我觉得我已经重现了问题,但使用了更简单的数据。

将过程分解为先排序然后子集让我发现这种情况下的排序不会生成数据帧对象

df <- data.frame(x = sample(1:50))
ndf <- df[order(df$x),]
print(class(ndf))
Run Code Online (Sandbox Code Playgroud)

产生

[1] "integer"
Run Code Online (Sandbox Code Playgroud)

尝试使用数据帧语法对结果“整数”ndf 对象进行子集化,例如

print(ndf[ndf$x < 5, ])
Run Code Online (Sandbox Code Playgroud)

显然会产生一个错误:

Error in ndf$x : $ operator is invalid for atomic vectors.
Run Code Online (Sandbox Code Playgroud)

进一步简化,我发现单独的子集化(不应用 order 函数)不会生成数据帧对象

ndf <- df[df$x < 5,]

class(ndf)
[1] "integer"
Run Code Online (Sandbox Code Playgroud)

事实证明,分离排序和子集的多列数据框确实按预期工作

df <- data.frame(x = sample(1:50), y = rnorm(50))

ndf <- df[order(df$x),]

print(ndf[ndf$x < 5, ])
Run Code Online (Sandbox Code Playgroud)

这解决了我原来的问题,但又引出了两个问题:

  1. 为什么返回的对象类型,如上所述基于 1 列数据帧测试用例,而不是数据帧?(我很欣赏一个 1 列的数据框只包含一个向量,但它仍然包含在一个数据框中?)
  2. 是否可以在 1 步中对多列数据帧进行排序和子集化?

MrF*_*ick 5

data.frame仅选择一列时,R 中的A 会自动简化为向量。这是一个常见且有用的简化,在这个问题中有更好的描述。当然,您可以使用drop=FALSE.

子集和排序是两种不同的操作。您应该分两个逻辑步骤(但可能是一行代码)来完成它们。这条线没有多大意义

df[order(df$x) & df$x < 5,]
Run Code Online (Sandbox Code Playgroud)

R 中的子集可以使用行索引向量(order()返回)或布尔值(<比较返回)完成。将它们混合(仅使用&)并不能说明 R 应该如何执行子集。但是你可以把它分成两个步骤subset()

subset(df[order(df$x),], x < 5)
Run Code Online (Sandbox Code Playgroud)

这首先进行排序,然后进行子集化。请注意,条件目录不再具体引用 的值df,它将从重新排序的 data.frame 中过滤数据。

像这样的操作是许多人喜欢使用dplyr库进行数据操作的原因之一。例如,这可以用

library(dplyr)
dd <- data.frame(x = sample(1:50))
dd %>% filter(x<5) %>% arrange(x)
Run Code Online (Sandbox Code Playgroud)