I would like to how to do a row wise sorting in csv using R. Here's the following data I have
Name English Math French
John 56 78 86
Sam 79 97 86
Viru 93 44 34
I want to perform row wise sorting for the above dataset. Like the following.
Name
John French 86 Math 78 English 56
Sam Math 97 French 86 English 79
Viru English 93 Math 44 French 34
Please do let me know how to approach
To sort each row of an R data frame in increasing order, we can use apply function for sorting the columns and then transpose the output. For example, if we have a data frame called df that contains 5 columns then each row of df can be sorted in increasing order by using the command t(apply(df,1,sort)).
If we need only to sort by rows, use apply with MARGIN=1 and assign the output back to the original columns after transposing the output. NOTE: But we may need to change the column names as sorting by row gives the new sorted values.
To sort a data frame in R, use the order( ) function. By default, sorting is ASCENDING. Prepend the sorting variable by a minus sign to indicate DESCENDING order.
If we need only to sort
by rows, use apply
with MARGIN=1
and assign the output back to the original columns after transposing the output.
df1[-1] <- t(apply(df1[-1], 1,
FUN=function(x) sort(x, decreasing=TRUE)))
df1
# Name English Math French
# 1 John 86 78 56
# 2 Sam 97 86 79
# 3 Viru 93 44 34
NOTE: But we may need to change the column names as sorting by row gives the new sorted values.
Another option will be use apply
separately to get the column names and the values, with Map
we get the corresponding columns, cbind
with the first column to have the output.
nMat <- `dim<-`(names(df1)[-1][t(apply(df1[-1], 1,
order, decreasing=TRUE))], dim(df1[-1]))
vMat <- t(apply(df1[-1], 1, sort, decreasing=TRUE))
cbind(df1[1], data.frame(Map(cbind, as.data.frame(nMat,
stringsAsFactors=FALSE), as.data.frame(vMat))))
# Name V1.1 V1.2 V2.1 V2.2 V3.1 V3.2
#1 John French 86 Math 78 English 56
#2 Sam Math 97 French 86 English 79
#3 Viru English 93 Math 44 French 34
Or another option is data.table
. We melt
the 'wide' format to 'long' format, grouped by 'Name', we order
the 'value' in decreasing order in 'i', get the Subset of Data.table (.SD
), create a new column ('N'), grouped by 'Name' and use dcast
to convert from 'long' to 'wide'.
library(data.table)
dcast(melt(setDT(df1), id.var='Name')[order(-value),
.SD, Name][, N:=paste0("Col", 1:.N) , .(Name)],
Name~N, value.var=c("variable", "value"))
# Name variable_Col1 variable_Col2 variable_Col3 value_Col1 value_Col2 value_Col3
#1: John French Math English 86 78 56
#2: Sam Math French English 97 86 79
#3: Viru English Math French 93 44 34
EDIT:
The above data.table
solution will not work in case you have 10 or more columns with values, because then col10
will preceed col2
in the ordering, even though higher values will be stored in col2
. To resolve this issue, you can use just number for the names of your new columns as in:
dcast(melt(setDT(df1), id.var='Name')[order(-value),
.SD, Name][, N:=1:.N , .(Name)],
Name~N, value.var=c("variable", "value"))
You can try:
cbind(x[1],matrix(paste(colnames(x)[apply(x[,2:4],1,order,decreasing=TRUE)+1],
apply(x[,2:4],1,sort,decreasing=TRUE)),ncol=3,byrow=TRUE))
# Name 1 2 3
#1 John French 86 Math 78 English 56
#2 Sam Math 97 French 86 English 79
#3 Viru English 93 Math 44 French 34
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With