为何dplyr的arrange对apply生成的字符型列报错,仅因子型生效?
The Problem Recap
You built a tibble with tidyverse, generated the Status column using mutate() combined with apply(), and noticed that calling arrange(Status) throws this error:
Error in arrange_impl(.data, dots) : Argument 1 is of unsupported type matrix
But converting Status to a factor fixes the issue, even though you’ve never had problems using arrange() with character columns before. You’re wondering if apply() is the culprit here—and you’re absolutely right.
What’s Actually Happening
The key issue is that your Status column isn’t actually a character vector—it’s a matrix in disguise. Here’s why:
- In the tidyverse pipeline,
.refers to a tibble (tbl_df). When you use.[, 2:7], you’re extracting columns 2-7 as another tibble, not a base R data frame or matrix. - When
apply()receives a tibble, it first converts it to a matrix. For row-wise sums (MARGIN = 1),apply()returns a column matrix (not a plain vector) when working with a matrix input. - When you combine this matrix with the logical vector from
.[, 8] > 0, R’s recycling rules turn the result into another matrix. - Finally,
ifelse()takes this matrix input and returns a matrix output—so yourStatuscolumn is a 6x1 matrix, not a character vector.
You can confirm this by running class(df$Status)—it’ll return matrix, not character. That’s why arrange() throws an error: it doesn’t support sorting by matrix columns. When you convert Status to a factor, as.factor() automatically flattens the matrix into a vector, which arrange() can handle.
The Fix: Ditch apply() for Tidyverse-Friendly Row Operations
Instead of using base R’s apply() (which plays poorly with tibbles), use tidyverse functions designed for row-wise calculations:
Option 1: Use rowSums() with across()
This is the most efficient approach for row sums:
library(tidyverse) df <- df %>% mutate( # Calculate row sum of columns 2-7 period_sum = rowSums(across(2:7)), # Generate Status as a proper character vector Status = ifelse(period_sum > 0 & `2018-04` > 0, "NOK", "OK") ) %>% select(-period_sum) # Clean up the helper column
Option 2: Use rowwise() + c_across()
If you need more flexibility (e.g., non-sum row-wise calculations), use rowwise():
df <- df %>% rowwise() %>% mutate( period_sum = sum(c_across(2:7)), Status = ifelse(period_sum > 0 & `2018-04` > 0, "NOK", "OK") ) %>% ungroup() %>% # Important to exit row-wise mode select(-period_sum)
Either way, the Status column will now be a plain character vector, and arrange(Status) will work exactly as you expect—no need to convert to a factor.
Why This Works
Tidyverse functions like across() and c_across() are designed to work with tibbles directly, returning vectors instead of matrices. This keeps your columns in the proper format for downstream dplyr operations like arrange().
内容的提问来源于stack exchange,提问作者stackinator

