1
votes

Répartissez les valeurs uniques (dans plusieurs colonnes) dans différentes colonnes et collez les valeurs agrégées

J'ai un dataframe comme ci-dessous:

structure(list(A1 = 3, A2 = 7, B1 = 5, B2 = 5, C1 = 1, C2 = 2, 
    C3 = 3, C4 = 4), class = "data.frame", row.names = c(NA, 
-1L))

Je souhaite répartir des valeurs uniques dans chaque colonne vers différentes colonnes à l'aide de data.table et coller la valeur additionnée (de la colonne "Valeur") sous chaque colonne Par exemple: la colonne col1 a 2 valeurs uniques A1 et A2. La somme de A1 est 3 et A2 est 7 De même, la colonne col2 a 2 valeurs uniques B1 et B2. La somme de B1 est 5 et B2 est 5

Cette opération sera effectuée pour chacune des colonnes col1, col2 et col3.

Le résultat attendu est comme ci-dessous

structure(list(Value = c(1, 2, 3, 4), col1 = structure(c(1L, 
1L, 2L, 2L), .Label = c("A1", "A2"), class = "factor"), col2 = structure(c(1L, 
2L, 2L, 1L), .Label = c("B1", "B2"), class = "factor"), col3 = structure(1:4, .Label = c("C1", 
"C2", "C3", "C4"), class = "factor")), class = "data.frame", row.names = c(NA, 
-4L))

Comment puis-je y parvenir en R?


6 Réponses :


1
votes

Je ne suis pas très acclimaté à data.table mais une solution tidyverse peut être,

# A tibble: 1 x 8
     A1    A2    B1    B2    C1    C2    C3    C4
  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1     3     7     5     5     1     2     3     4

ce qui donne, p >

library(dplyr)
library(tidyr)

df %>% 
 pivot_longer(starts_with('col')) %>% 
 group_by(value) %>% 
 summarise(res = sum(Value)) %>% 
 pivot_wider(names_from = value, values_from = res)


0 commentaires

3
votes

La version data.table de la réponse de @Sotos serait:

library(data.table)

dcast(melt(setDT(df), 'Value')[, .(Total = sum(Value)), value],
           rowid(value)~value, value.var = 'Total')

#   value A1 A2 B1 B2 C1 C2 C3 C4
#1:     1  3  7  5  5  1  2  3  4

Vous n'avez probablement pas besoin de la colonne value vous pouvez donc le supprimer en ajoutant [ value: = NULL] []


4 commentaires

hé ... je viens de finir de le faire en DT mais c'est plus encombrant que ça donc je ne prendrai pas la peine d'ajouter


Il existe peut-être une version plus soignée de ceci: P mais j'utilise aussi plus de tidyverse que de data.table .


Je pense qu'ils ont combiné dcast / melt en un seul, mais je pourrais le confondre avec reshape2 ... pas sûr


Il y a le paramètre fun.aggregate dans dcast mais je suppose qu'il ne pourra pas faire la somme par groupe.



1
votes

Version de Base R (un autre wannabe data.table):

    A1 A2 B1 B2 C1 C2 C3 C4
res  3  7  5  5  1  2  3  4

t(unstack(
    with(reshape(df, direction="long", 
             varying=grep("^col", names(df), value=TRUE), sep=""),
     aggregate(formula=Value~col, FUN=sum)), 
  form=Value~col))


0 commentaires

1
votes

Voici une autre solution de base R

df <- structure(list(Value = c(1, 2, 3, 4), col1 = structure(c(1L, 
1L, 2L, 2L), .Label = c("A1", "A2"), class = "factor"), col2 = structure(c(1L, 
2L, 2L, 1L), .Label = c("B1", "B2"), class = "factor"), col3 = structure(1:4, .Label = c("C1", 
"C2", "C3", "C4"), class = "factor")), class = "data.frame", row.names = c(NA, 
-4L))

telle que

> dfout
    A1 A2 B1 B2 C1 C2 C3 C4
res  3  7  5  5  1  2  3  4

DONNÉES

XXX


2 commentaires

J'aime cette solution, mais que faire s'il y a une 4ème colonne, col4 , ou en général plus de colonnes? Comment modifieriez-vous cela?


@Edward bonne question! alors vous pouvez utiliser seq_along (df) [- 1] au lieu de 2: 4 pour les cas généraux. voir mes mises à jour



0
votes

Voici une autre option:

df <- structure(list(Value = c(1, 2, 3, 4), col1 = structure(c(1L, 
1L, 2L, 2L), .Label = c("A1", "A2"), class = "factor"), col2 = structure(c(1L, 
2L, 2L, 1L), .Label = c("B1", "B2"), class = "factor"), col3 = structure(1:4, .Label = c("C1", 
"C2", "C3", "C4"), class = "factor")), class = "data.frame", row.names = c(NA, 
-4L))

data:

library(data.table)
x <- rbindlist(lapply(paste0("col", 1:3), function(b) df[, sum(Value), b]), 
    use.names=FALSE)

setDT(setNames(as.list(x$V1), x$col1))[]


0 commentaires

0
votes

Vous pouvez également le résoudre comme suit:

library(data.table)
melt(setDT(df), "Value")[, .(TOT = sum(Value)), value][, setNames(as.list(TOT), value)]

#       A1    A2    B1    B2    C1    C2    C3    C4
# 1:     3     7     5     5     1     2     3     4


0 commentaires