【问题标题】:How can I sort the columns of a large data frame based on specific criteria?如何根据特定条件对大型数据框的列进行排序?
【发布时间】:2020-05-31 10:33:23
【问题描述】:

我想根据特定的理由对大型数据框(大约 14000 个变量)的列进行排序。

列名具有以下结构(Condition_Sleepstage_Parameter_Electrode_Nightpart):

 [1] "Adapt_N2_negLengthLoc_C3_firstHour"          "Adapt_N3_negLengthLoc_C3_firstHour"         
  [3] "Adapt_NREM_negLengthLoc_C3_firstHour"        "Book_N2_negLengthLoc_C3_firstHour"          
  [5] "Book_N3_negLengthLoc_C3_firstHour"           "Book_NREM_negLengthLoc_C3_firstHour"

R 的列按纯字母结构排序,但我希望它们按基于以下系统的逻辑顺序排列:

首先,变量应该在每个参数的块中呈现。 (顺序:“negLengthLoc”、“posLength”、“wholeLength”、“negPeak”、“nbnegPeaks”、“initialMeannegSlope”、“finalMeannegSlope”、“initialMaxnegslope”、“finalMaxnegslope”、“posPeak”、“nbposPeaks”、“initialMeannposSlope” , "finalMeanposSlope", "initialMaxposSlope", "PeaktoPeak", "Number", "Density")

在这些块中,最高层次的层次应该是由于条件。 (顺序:“Adapt”、“NoFilter”、“Filter”、“Book”)。

此后,下一个层次结构应该由 Electrode 定义。 (顺序:“F3”、“Fz”、“F4”、“C3”、“Cz”、“C4”、“P3”、“Pz”、“P4”、“O1”、“O2”)。

之后按 Nightpart(顺序:“firstHour”、“firstQuarter”、“secondQuarter”、“thirdQuarter”、“fourthQuarter”、“wholeNight”),最后按 Sleepstage(“order:“N2”、“N3”、“非快速眼动”)。

生成的顺序应如下所示:

[1] "Adapt_N2_negLengthLoc_F3_firstHour"          "Adapt_N3_negLengthLoc_F3_firstHour"
[3] "Adapt_NREM_negLengthLoc_F3_firstHour"          "Adapt_N2_negLengthLoc_F3_firstQuarter"
[5] "Adapt_N3_negLengthLoc_F3_firstQuarter"          "Adapt_NREM_negLengthLoc_F3_firstQuarter"
[7] "Adapt_N2_negLengthLoc_F3_secondQuarter"          "Adapt_N3_negLengthLoc_F3_secondQuarter"
[9] "Adapt_NREM_negLengthLoc_F3_secondQuarter"          "Adapt_N2_negLengthLoc_F3_thirdQuarter"
[11] "Adapt_N3_negLengthLoc_F3_thirdQuarter"          "Adapt_NREM_negLengthLoc_F3_thirdQuarter"
[13] "Adapt_N2_negLengthLoc_F3_fourthQuarter"          "Adapt_N3_negLengthLoc_F3_fourthQuarter"
[15] "Adapt_NREM_negLengthLoc_F3_fourthQuarter"          "Adapt_N2_negLengthLoc_F3_wholeNight"
[17] "Adapt_N3_negLengthLoc_F3_wholeNight"           "Adapt_NREM_negLengthLoc_F3_wholeNight"
[19] "Adapt_N2_negLengthLoc_Fz_firstHour"           "Adapt_N3_negLengthLoc_Fz_firstHour"
...

我希望有人可以帮助我,如果有任何进一步的问题,我当然很乐意提供更多信息!

提前致谢!

【问题讨论】:

  • 欢迎来到 SO!您的列名中有很多信息。是否有必要将此信息存储为列名?如果您将信息存储在单独的列中(例如parameter 的一列,Condition 的一列等),则按照数据整齐的原则处理数据会更容易:r4ds.had.co.nz/tidy-data.html
  • 感谢您的建议!由于这些数据会进一步分发给将使用 SPSS 的学生,因此有必要以这种“极端”宽格式保存数据。

标签: r sorting character alphabetical


【解决方案1】:

mtcars 数据为例,可以通过创建具有所需顺序的向量并在列规范中使用提取运算符的[ 形式来对数据框中的列进行重新排序。

首先,我们将使用colnames() 提取列的原始顺序并打印出来

theNames <- colnames(mtcars)
theNames

> theNames
 [1] "mpg"  "cyl"  "disp" "hp"   "drat" "wt"   "qsec" "vs"   "am"   "gear" "carb"

接下来,我们将通过创建一个reorderedNames 向量并将其与[ 一起使用,将所有整数列移动到数据框的左侧。

reorderedNames <- c("cyl" , "vs" ,  "am" ,  "gear" ,"carb","disp" ,
                     "drat", "wt" ,  "qsec", "mpg")
mtcars[,reorderedNames]

...以及输出的前几行:

> mtcars[,reorderedNames]
                    cyl vs am gear carb  disp drat    wt  qsec  mpg
Mazda RX4             6  0  1    4    4 160.0 3.90 2.620 16.46 21.0
Mazda RX4 Wag         6  0  1    4    4 160.0 3.90 2.875 17.02 21.0
Datsun 710            4  1  1    4    1 108.0 3.85 2.320 18.61 22.8
Hornet 4 Drive        6  1  0    3    1 258.0 3.08 3.215 19.44 21.4
Hornet Sportabout     8  0  0    3    2 360.0 3.15 3.440 17.02 18.7
Valiant               6  1  0    3    1 225.0 2.76 3.460 20.22 18.1
Duster 360            8  0  0    3    4 360.0 3.21 3.570 15.84 14.3
Merc 240D             4  1  0    4    2 146.7 3.69 3.190 20.00 24.4

为大型数据框自动执行此过程

在 OP 中,问题引用了具有大量列的数据框。为了扩展此过程以自动对列进行排序,至少有两种主要方法。

  1. 以允许按所需顺序对列名进行排序的方式处理数据框中的列名,或者
  2. 使用pivot_longer() 将列名拆分为所需的分组变量,从而创建一个窄格式的整洁数据集。

我们将使用来自 OP 的数据来说明方法 1。

columnName <- c("Adapt_N2_negLengthLoc_C3_firstHour","Adapt_N3_negLengthLoc_C3_firstHour",         
"Adapt_NREM_negLengthLoc_C3_firstHour","Book_N2_negLengthLoc_C3_firstHour",          
"Book_N3_negLengthLoc_C3_firstHour","Book_NREM_negLengthLoc_C3_firstHour")
splitCols <- strsplit(columnName,"_")

results <- lapply(splitCols,function(x){
     parameter <- x[3]
     condition <- x[1]
     electrode <- x[4]
     nightpart <- x[5]
     sleepstage <- x[2]
     data.frame(parameter,condition,electrode,nightpart,sleepstage)
})

colsData <- do.call(rbind,results)
# add original column names back into data
colsData <- cbind(columnName,colsData)
# convert to factors, specifying the factor order for sorting
conditionOrder <- c("Adapt", "NoFilter", "Filter", "Book")
parameterOrder <- c("negLengthLoc", "posLength", "wholeLength", "negPeak", "nbnegPeaks", 
                    "initialMeannegSlope", "finalMeannegSlope", "initialMaxnegslope", 
                    "finalMaxnegslope", "posPeak", "nbposPeaks", "initialMeannposSlope",
                    "finalMeanposSlope", "initialMaxposSlope", "PeaktoPeak", "Number", "Density")
electrodeOrder <- c("F3", "Fz", "F4", "C3", "Cz", "C4", "P3", "Pz", "P4", "O1", "O2")
nightpartOrder <- c("firstHour", "firstQuarter", "secondQuarter", "thirdQuarter", "fourthQuarter", "wholeNight") 
sleepstageOrder <- c("N2", "N3", "NREM")
colsData$condition <- factor(colsData$condition,levels = conditionOrder,ordered = TRUE)
colsData$parameter <- factor(colsData$parameter,levels = parameterOrder,ordered = TRUE)
colsData$electrode <- factor(colsData$electrode,levels = electrodeOrder,ordered = TRUE)
colsData$nightpart <- factor(colsData$nightpart,levels = nightpartOrder,ordered = TRUE)
colsData$sleepstage <- factor(colsData$sleepstage,levels = sleepstageOrder,ordered = TRUE)

# finally, sort by factors & create a vector for column number
library(dplyr)
colsData <- arrange(colsData,condition,parameter,electrode,nightpart,sleepstage)
colsData$colId <- 1:nrow(colsData)
colsData

...和输出:

> colsData
                            columnName    parameter condition electrode nightpart
1   Adapt_N2_negLengthLoc_C3_firstHour negLengthLoc     Adapt        C3 firstHour
2   Adapt_N3_negLengthLoc_C3_firstHour negLengthLoc     Adapt        C3 firstHour
3 Adapt_NREM_negLengthLoc_C3_firstHour negLengthLoc     Adapt        C3 firstHour
4    Book_N2_negLengthLoc_C3_firstHour negLengthLoc      Book        C3 firstHour
5    Book_N3_negLengthLoc_C3_firstHour negLengthLoc      Book        C3 firstHour
6  Book_NREM_negLengthLoc_C3_firstHour negLengthLoc      Book        C3 firstHour
  sleepstage colId
1         N2     1
2         N3     2
3       NREM     3
4         N2     4
5         N3     5
6       NREM     6
> 

此时我们可以使用colsData$columnName对原始数据框进行排序。

【讨论】:

  • 感谢您的回答。不幸的是,这并不能真正解决我的问题,因为它需要一个包含所需顺序的排序向量。但是,我的问题是我真的不想手动订购这 14.000 个变量名:-/
  • @ChristopherHöhn - 感谢克里斯托弗的反馈。请参阅我使用问题中包含的数据的自动解决方案的更新答案。
【解决方案2】:

您必须将列名拆分为它所包含的不同部分。这是通过 stringr 包中的 str_split 完成的。它为每个列名生成一个包含一个条目的列表,每个条目都是具有不同部分的字符向量。 为了创建具有不同部分的新列,我使用 purrr 包中的 map_chr 来访问每个列名的相应条目。然后,排列列。要获得所需的顺序,请将字符转换为factor 并使用levels 指定顺序。列的新顺序由列rowid表示:

old_order <- data.frame(col_names = c("Adapt_N2_negLengthLoc_C3_firstHour",          "Adapt_N3_negLengthLoc_C3_firstHour",        
               "Adapt_NREM_negLengthLoc_C3_firstHour",        "Book_N2_negLengthLoc_C3_firstHour",          
               "Book_N3_negLengthLoc_C3_firstHour",           "Book_NREM_negLengthLoc_C3_firstHour",
               "Adapt_N2_negLengthLoc_Fz_firstHour",           "Adapt_N3_negLengthLoc_Fz_firstHour"))

library(dplyr)
library(stringr)

splitted_names <- str_split(old_order$col_names, "_")

new_order <- old_order %>% 
  tibble::rowid_to_column() %>% 
  mutate(Condition = purrr::map_chr(splitted_names, `[`, 1),
         Sleepstage = purrr::map_chr(splitted_names, `[`, 2),
         Parameter = purrr::map_chr(splitted_names, `[`, 3),
         Electrode = purrr::map_chr(splitted_names, `[`, 4),
         Nightpart = purrr::map_chr(splitted_names, `[`, 5)) %>% 
  arrange(factor(Parameter, levels = c("negLengthLoc", "posLength", "wholeLength", "negPeak", "nbnegPeaks", "initialMeannegSlope", "finalMeannegSlope", "initialMaxnegslope", "finalMaxnegslope", "posPeak", "nbposPeaks", "initialMeannposSlope", "finalMeanposSlope", "initialMaxposSlope", "PeaktoPeak", "Number", "Density")),
          factor(Condition, levels = c("Adapt", "NoFilter", "Filter", "Book")),
          factor(Electrode, levels = c("F3", "Fz", "F4", "C3", "Cz", "C4", "P3", "Pz", "P4", "O1", "O2")),
          factor(Nightpart, levels = c("firstHour", "firstQuarter", "secondQuarter", "thirdQuarter", "fourthQuarter", "wholeNight")),
          factor(Sleepstage, levels = c("N2", "N3", "NREM"))) %>% 
  pull(rowid)

old_order$col_names[new_order]
[1] Adapt_N2_negLengthLoc_Fz_firstHour   Adapt_N3_negLengthLoc_Fz_firstHour   Adapt_N2_negLengthLoc_C3_firstHour  
[4] Adapt_N3_negLengthLoc_C3_firstHour   Adapt_NREM_negLengthLoc_C3_firstHour Book_N2_negLengthLoc_C3_firstHour   
[7] Book_N3_negLengthLoc_C3_firstHour    Book_NREM_negLengthLoc_C3_firstHour 
8 Levels: Adapt_N2_negLengthLoc_C3_firstHour ... Book_NREM_negLengthLoc_C3_firstHour

既然您已经将信息分成不同的列,我建议您将完整的数据集放入tidy (long) format

【讨论】:

    猜你喜欢
    • 2020-06-18
    • 2022-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多