1
votes

Comment ajouter une colonne avec le même nom de colonne dans un bloc de données

J'ai un ensemble de données avec des milliers de colonnes dont certaines colonnes ont le même nom de colonne. Je veux fusionner la colonne avec le même nom de colonne de sorte que les valeurs soient ajoutées sous forme de lignes. Et, pour les colonnes qui n'ont pas de colonne avec le même nom de colonne, 0 est ajouté dans les lignes.

Clarification : ci-dessous est juste un exemple, les données réelles set que j'ai a des milliers de colonnes et beaucoup d'entre elles ont des noms de colonnes qui sont en double et beaucoup ne le sont pas.

Exemple de données d'entrée

Col_1 Col_2
  1    5
  2    5
  3    5
  4    5
  5    0
  6    0
  7    0 
  8    0
  9    0
 10    0
 11    0
 12    0
 13    0
 14    0
 15    0
 16    0


0 commentaires

3 Réponses :


0
votes

Essayez ceci. La logique n'est pas claire: EDIT :: Je pense que le mieux que l'on puisse faire est simplement de fondre les données comme ceci

      Col_1 Col_2
1      1     5
2      2     5
3      3     5
4      4     5
5      5     0
6      6     0
7      7     0
8      8     0
9      9     0
10    10     0
11    11     0
12    12     0
13    13     0
14    14     0
15    15     0
16    16     0

Vous pouvez procéder ainsi, mais je pense que laisser les données fondues, c'est mieux.

  library(tidyverse)
    df %>% 
  gather(key,value,-Col_2) %>% 
  arrange(value) %>% 
  rename(Col_1=value) %>% 
  mutate(Col_2=ifelse(Col_1<=4,5,0)) %>% 
  select(Col_1,everything(),-key)

Résultat (fondu): La question est alors de savoir comment gérer les doublons.

 ID    Value
   <chr> <int>
 1 Col_1     1
 2 Col_1     2
 3 Col_1     3
 4 Col_1     4
 5 Col_1     5
 6 Col_2     5
 7 Col_2     5
 8 Col_2     5
 9 Col_2     5
10 Col_1     6
11 Col_1     7
12 Col_1     8
13 Col_1     9
14 Col_1    10
15 Col_1    11
16 Col_1    12
17 Col_1    13
18 Col_1    14
19 Col_1    15
20 Col_1    16

Original: p>

library(reshape2)
df1 %>% 
  ungroup() %>% 
  dcast(Value~ID,fun=mean) %>% 
  mutate(Col_2=ifelse(Col_1<=4,5,0)) %>% 
  select(-Value)

Résultat:

library(tidyverse)
df1<-df %>% 
  gather("ID","Value") %>% 
  group_by(ID) %>% 
  arrange(Value)

df1$ID<-str_replace_all(df1$ID,"Col_1.\\d","Col_1")


7 commentaires

. @ NelsonGon - L'exemple que j'ai donné n'est pas le vrai scénario, j'ai des milliers de colonnes et parmi elles certaines ont un nom de colonne en double et d'autres pas.


Comment voulez-vous traiter les doublons?


. @ NelsonGon - Désolé si cela prête à confusion. Je veux simplement fusionner chaque nom de colonne en double (et ses données) de la même manière que celle expliquée dans l'exemple ci-dessus en question.


. @ NelsonGon - Merci, mais vous pensez toujours que le nom de la colonne est Col_1 . Je ne pense pas que cela fonctionnera sur des données volumineuses où je ne sais pas quel est le nom de colonne et que je veux simplement que cela se produise de manière dynamique.


J'ai raté cette partie. Pourriez-vous montrer le nom des colonnes


. @ NelsonGon - Cela peut être n'importe quoi. Selon les exemples de données dans ma question, est-il possible d'écrire la logique de telle sorte qu'elle lit colnames () puis l'utilise pour trouver des colonnes en double et finalement fusionne comme je l'ai expliqué en question?


@ NelsonGon- Merci. Désolé, au fur et à mesure que je lis plus, je réalise que c'est bien si c'est fait avec tidyverse () . Cependant, je ne fais que commencer avec ce package. Peut être inférieur à réponse par @KeqiangLi peut vous aider. J'essaye de résoudre un problème que j'exécute avec lui.



1
votes

Voici ma méthode qui implique un travail manuel. Supposons que votre ensemble de données se trouve dans la variable test

library(tidyverse)

# testing data
test <- data.frame(c(1,2,3), c(7,8,9), c(4,5,6), c(10,11,12), c(100, 101, 102)) %>%
  set_names(c("Col_1", "Col_2", "Col_1", "Col_2", "Col_3"))

col_names <- names(test)

# find all columns that have duplicated columns
dup_names <- col_names[duplicated(col_names)]

# make the column names unique so it will work with tidyr
renamed_test <- test %>%
  set_names(str_c(col_names, "-", 1:ncol(test)))

unique_data <- test[!(duplicated(col_names) | duplicated(col_names, fromLast = TRUE))]

# for each duplicated column name, merge all columns that have the same name
dup_names %>% map(function(col_name) {
  renamed_test %>%
    select(starts_with(col_name)) %>% 
    gather %>% # bind rows
    select(-1) %>% # merged value is the last column
    set_names(c(col_name)) # rename the column name back to its original name
}) %>% bind_cols

result <- bind_rows(tmp_result, unique_data)

Edit:

J'ai généralisé la solution afin qu'elle trouve automatiquement toutes les colonnes et lignes dupliquées lier chacun

# may only require some of the packages of tidyverse
library(tidyverse)

# this will give all column unique names
renamed_test <- test %>%
                set_names(str_c(names(test), 1:ncol(test)))

# then for each duplicated column name, they now start with the same prefix;
# so select all these columns and use gather to append them one after another,
# and finally rename the merged column back to the original name
bound_col_1 <- renamed_test %>%
               select(starts_with("Col_1")) %>%
               gather %>%
               transmute(Col_1 = value)

# repeat this for 'Col_2'
# .....

# last, column bind all these results
bind_cols(bound_col_1, bound_col_2, [potentiall other variables])

Ceci est délicat lorsque vous essayez de lier les colonnes car les données fusionnées peuvent avoir un numéro de ligne différent. Vous pouvez comparer la longueur à chaque fois lors de la fusion et remplir la liste plus courte en ajoutant des 0.


5 commentaires

. @ KeqiangLi - Désolé, l'exemple que j'ai donné n'est pas le vrai scénario, j'ai des milliers de colonnes et parmi elles certaines ont un nom de colonne en double et d'autres pas. Je veux simplement fusionner chaque nom de colonne en double (et ses données) de la même manière que celle expliquée dans l'exemple ci-dessus en question.


C'est toujours faisable, il suffit de construire en fonction de mon exemple. Tout d'abord, il est très facile de déterminer toutes les colonnes qui ont des noms de colonne en double par dup_names <- names (test) [duplicated (names (test))] . Et puis vous pouvez simplement parcourir le vecteur et utiliser la logique dans ma réponse


@ChetanArvindPatil J'ai mis à jour la solution et maintenant elle devrait bien se généraliser.


. @ KeqiangLi - Merci. Je rencontre une Erreur dans cbind_all (x): l'argument 2 doit être de longueur 6, pas 102 . La valeur 6 et 102 est spécifique à mon big data, puisque je ne suis pas encore bon en tidyverse () , je ne sais pas comment pour résoudre ce problème. Des suggestions s'il vous plaît?


@ChetanArvindPatil lors de l'utilisation de bind_cols, les deux blocs de données doivent avoir le même numéro de ligne si vous imaginez comment fonctionne la liaison de colonne (ce n'est pas spécifique à 'tidyverse', la base R l'exigera toujours). La «fusion automatique» ne se produira pas simplement par magie, mais nécessite le véritable jeu de données avec beaucoup de débogage. Si vous pouvez mettre quelques points d'arrêt et imprimer les variables générées en cours de route, et essayer d'ajouter des lignes pour que deux blocs de données aient le même nombre de lignes, vous serez en mesure de le comprendre.



0
votes

Voici une réponse assez compliquée. Une partie du code est un peu maladroite, mais c'est une solution générale.

Solution

df <- read.table(header = T, text = "
Col_1 Col_1 Col_1 Col_1 Col_2
  1     2     3     4   5
5     6     7     8   5
9    10    11    12   5
13    14    15    16   5") %>% 
  setNames(c("Col_1", "Col_1", "Col_1", "Col_1", "Col_2"))

Données

library(tidyverse)
library(magrittr)

# function to create lookup table, matching duplicate column names to syntactically valid names 
rel <- function(x) {x %>% 
  colnames %>% 
  make.names(., unique = TRUE) %>% 
  as.data.frame() %>% 
  mutate(names(x)) %>% 
  setNames(c("New", "Old")) }

# create lookup table to match old and new column names
lookup <- rel(df)

# gather df into long format
df_long <- df %>% 
  setNames(lookup$New) %>% 
  gather(var, value)

# match new names to original names
df_colnames <- lapply(1:length(unique(lookup$Old)), function(x) grepl(unique(lookup$Old)[x], df_long$var)) %>% 
  setNames(unique(lookup$Old)) %>% 
  as.data.frame

# vector replacing new syntactically valid names with original names
column <- lapply(names(df_colnames), function(x) ifelse(df_colnames[, x], x, F)) %>% 
  setNames(unique(lookup$Old)) %>% 
  as.data.frame %>% 
  unite(comb, sep = "") %>% 
  magrittr::extract(, "comb") %>% 
  gsub("FALSE", "", .)

# put original columns into lists
final_list <- df_long %>% 
  mutate(var = column) %>% 
  arrange(var, value) %>% 
  split(.$var) %>% 
  map(~select_at(.x, c("value"))) %>% 
  lapply(function(x) x$value)

# create vectors of zeros to append to original data
final_list_extend <- sapply(abs(unlist(lapply(final_list, length)) - max(unlist(lapply(final_list, length)))), function(x) rep(0, x))

# append zeros to original data and rename columns to match original names
output <- sapply(1:length(final_list), function(x) c(final_list[[x]], final_list_extend[[x]])) %>% 
  as_data_frame %>% 
  setNames(unique(lookup$Old))

#show result
output

# A tibble: 16 x 2
   Col_1 Col_2
   <dbl> <dbl>
 1     1     5
 2     2     5
 3     3     5
 4     4     5
 5     5     0
 6     6     0
 7     7     0
 8     8     0
 9     9     0
10    10     0
11    11     0
12    12     0
13    13     0
14    14     0
15    15     0
16    16     0

p>


0 commentaires