2
votes

Quand et comment utiliser as.name () contre get () dans data.table (ex. En boucle sur des colonnes)?

Ma table de données dt0 est:

 Error in `[.data.table`(dt0, , `:=`(as.name(paste0(c, "_t")), as.name(c) *  : 
 LHS of := must be a symbol, or an atomic vector (column names or positions).

ANSWERx sont des pourcentages. SCORE100 est calculé comme SCORE100: = (100 * ANSWER1 * ANSCOUNT + 75 * ANSWER2 * ANSCOUNT + 50 * ANSWER3 * ANSCOUNT + 25 * ANSWER4 * ANSCOUNT) / (ANSWER1 * ANSCOUNT + ANSWER2 * ANSCOUNT + ANSWER3 * ANSCOUNT + ANSWER4 * ANSCOUNT + ANSWER5 * ANSCOUNT)]

Afin de recalculer SCORE100 pour toutes les lignes de mon ensemble de données, Je dois automatiquement (en boucle) multiplier tous les ANSWERx par ANSCOUNT dans chaque ligne, puis ajouter toutes les multiplications obtenues, puis diviser par la somme de tous les ANSCOUNT code>.

Pouvez-vous aider s'il vous plaît, quelque chose comme ci-dessous:

    for (c in paste0("ANSWER",1:5)) {
      dt0[, as.name(paste0(c,"_t")):= as.name(c)*"ANSCOUNT", , with=T]
    }

Merci.

Voici l'erreur. Comment le comprendre et comment le faire correctement?

ANSWER1 ANSWER2 ANSWER3 ANSWER4 ANSWER5 ANSCOUNT   SCORE100
 21      37      16      14      11     200784       61
 20      37      16      15      11     177165       60


3 commentaires

Une sous-question: Quel code créera automatiquement N nouvelles colonnes ANSWER1_t , ...., ANSWERN_t , qui sont égales à ANSWER1 * ANSCOUNT , ... ANSWERN * ANSCOUNT ?


Je souhaite toujours savoir comment / quand utiliser as.name (x) ou get (x) avec data.table , où x est passé en paramètre (d'une boucle ou d'une fonction). Pouvez-vous me donner des exemples de bonne utilisation de ceux-ci, s'il vous plaît? Ce serait formidable si l'aide / manuel de 'data.table' incluait également ces exemples ...


as.name ne convient que si vous créez une expression et appliquez eval , je pense. Ici, vous pouvez faire for (c in paste0 ("ANSWER", 1: 5)) dt0 [ paste0 (c, "_ t"): = get (.. c) * ANSCOUNT] Le point La notation -dot est assez récente, utilisée pour clarifier que c se réfère à une variable "un niveau supérieur" de la table


3 Réponses :


7
votes

Pour répondre à la question générale - " Quand et comment utiliser as.name () contre get () dans data.table? ".
D'après mon expérience, cela est rarement nécessaire lorsque vous pouvez utiliser les méthodes de programmation R existantes:

Une approche fonctionnelle similaire à l'autre réponse (maintenant supprimée):

dt0[, 
  newcol := Reduce(`+`, Map(`*`, c(100,75,50,25,0), .SD)) / Reduce(`+`, .SD),
  .SDcols = ANSWER1:ANSWER5
]

#   ANSWER1 ANSWER2 ANSWER3 ANSWER4 ANSWER5 ANSCOUNT SCORE100   newcol
#1:      21      37      16      14      11   200784       61 60.85859
#2:      20      37      16      15      11   177165       60 60.10101

Explication:

Mappez le facteur de pondération de 100-to-0 au code ANSWER1: ANSWER5 correspondant > colonnes, puis Réduisez les ensemble à l'aide d'une fonction + . En d'autres termes, 100 * ANSWER1 + 75 * ANSWER2 + 50 * ANSWER3 ... etc.

Utilisez ensuite les mêmes Réduire et + pour former le dénominateur de l'équation.

Je pense que la multiplication par ANSCOUNT est inutile car elle l'est à la fois au numérateur et au dénominateur.


1 commentaires

Une façon plus compliquée d'utiliser Réduire: DT [ Réduire (`+`, Réduire (`+`, .SD [ - longueur (.SD), avec = FALSE], accumuler = TRUE)) / Réduire ( `+`, .SD) * 25, .SDcols = REPONSE1: REPONSE5]



4
votes

Cela ne pourra peut-être pas rivaliser en termes de vitesse avec data.table mais avec une option de base R utilisant sweep et rowSums

m <- as.matrix(dt0[,.SD,.SDcols=ANSWER1:ANSWER5])
m %*% seq(100,0,-25) /rowSums(m)

Ou sans utiliser sweep

rowSums(t(t(dt0[,1:5]) * seq(100,0,-25)))/rowSums(dt0[, 1:5])

Les deux approches ci-dessus convertissent implicitement le data.table en matrice et exécute le calcul. Nous pouvons avoir une légère amélioration de la vitesse en utilisant la multiplication matricielle et en évitant l'opération de sous-ensemble deux fois. (merci à @nicola).

rowSums(sweep(dt0[,1:5],2, seq(100,0,-25), FUN = "*"))/rowSums(dt0[, 1:5])
#[1] 60.859 60.101


3 commentaires

J'imagine que ce sera en fait très compétitif. :-RÉ


@thelatemail mais il perd sa valeur de data.table je crois.


Une petite amélioration dans ce sens pourrait être l'utilisation de la multiplication matricielle (% *% ): m <-as.matrix (dt0 [. SD, .SDcols = ANSWER1: ANSWER5] ); m% *% c (100,75,50,25,0) / rowSums (m) (dans vos lignes, la coersion en matrice est implicite).



0
votes

Je viens de trouver à Attribution / Référencement dynamique d'un nom de colonne dans data.table (en i, j et par) l'interrelation entre les deux:

get(strFactor)

est la même

 eval(as.name(strFactor)) 

à la seule différence que le premier est "plus sûr" que le second ( plus précisément, get ne fonctionne pas dans certaines anciennes versions de certains packages (par exemple dans les anciennes versions de data.table )

Donc, avec cette mise en garde à l'esprit, l'un ou l'autre de ces deux peut être utilisé - lors de la boucle dans les colonnes!


0 commentaires