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 :
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)
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] []
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.
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))
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
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
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))[]
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
stackoverflow.com/help/someone-answers