5

This is my dataframe:

    df<-list(structure(list(Col1 = structure(1:6, .Label = c("A", "B", 
"C", "D", "E", "F"), class = "factor"), Col2 = structure(c(1L, 
2L, 3L, 2L, 4L, 5L), .Label = c("B", "C", "D", "F", "G"), class = "factor")), class = "data.frame", row.names = c(NA, 
-6L)), structure(list(Col1 = structure(c(1L, 4L, 5L, 6L, 2L, 
3L), .Label = c("A", "E", "H", "M", "N", "P"), class = "factor"), 
    Col2 = structure(c(1L, 2L, 3L, 2L, 4L, 5L), .Label = c("B", 
    "C", "D", "F", "G"), class = "factor")), class = "data.frame", row.names = c(NA, 
-6L)), structure(list(Col1 = structure(c(1L, 4L, 6L, 5L, 2L, 
3L), .Label = c("A", "W", "H", "M", "T", "U"), class = "factor"), 
    Col2 = structure(c(1L, 2L, 3L, 2L, 4L, 5L), .Label = c("B", 
    "C", "D", "S", "G"), class = "factor")), class = "data.frame", row.names = c(NA, 
-6L))) 

I want to extract col1=df[[1]][1] as a dataframe. Then col1 of the second position of this list I want to merge to the df[[1]][1], then I will have a dataframe with 2 columns. After this I want to merge the column 1 of the third position of the list to the dataframe with two columns, then I will have a dataframe with 3 columns.

In other words my dataframe should have 3 columns, all the first columns of each entry of my list.

The dplyr package can helpme to do this?

Any help?

1
  • @SalmanLashkarara I edited the question Commented Sep 19, 2018 at 18:13

5 Answers 5

5

You can use lapply to extract the three columns named "Col1 in one go. Then set the names of the result.

col1 <- as.data.frame(lapply(df, '[[', "Col1"))
names(col1) <- letters[seq_along(col1)]

col1
#  a b c
#1 A A A
#2 B M M
#3 C N U
#4 D P T
#5 E E W
#6 F H H

Choose any other column names that you might find better.

A dplyr way could be

df %>% 
  unlist(recursive = FALSE) %>%
  as.data.frame %>%
  select(., starts_with("Col1"))
#  Col1 Col1.1 Col1.2
#1    A      A      A
#2    B      M      M
#3    C      N      U
#4    D      P      T
#5    E      E      W
#6    F      H      H
Sign up to request clarification or add additional context in comments.

Comments

5

With map_dfc from purrr:

library(purrr)

map_dfc(df, `[`, 1)

Output:

  Col1 Col11 Col12
1    A     A     A
2    B     M     M
3    C     N     U
4    D     P     T
5    E     E     W
6    F     H     H

4 Comments

Or even just map_dfc(df, "Col1") or map_dfc(df, 1)
@CalumYou Both of these give error: Error in cbind_all(x) : Not compatible with STRSXP: [type=NULL]. because map(df, 1) returns a list of vectors, not list of dataframes
I cannot reproduce this error, see my reprex in complementary answer. Using purrr 0.2.5
Note that map_dfc(df, 1) does not work with dplyr_0.7.4 but my solution does.
2

Alternative use of map_dfc making use of purrr's concise element extraction syntax that allows specifying elements of elements by name or position. The first is, for example, equivalent to

map_dfc(df, `[[`, 1)

which differs from the use of [ in that the columns will not be named variations of Col1 and just get V names instead, which may be desirable since names like Col11 and Col12 may be confusing.

df <- list(structure(list(Col1 = structure(1:6, .Label = c("A", "B", "C", "D", "E", "F"), class = "factor"), Col2 = structure(c(1L, 2L, 3L, 2L, 4L, 5L), .Label = c("B", "C", "D", "F", "G"), class = "factor")), class = "data.frame", row.names = c(NA, -6L)), structure(list(Col1 = structure(c(1L, 4L, 5L, 6L, 2L, 3L), .Label = c("A", "E", "H", "M", "N", "P"), class = "factor"), Col2 = structure(c(1L, 2L, 3L, 2L, 4L, 5L), .Label = c("B", "C", "D", "F", "G"), class = "factor")), class = "data.frame", row.names = c(NA, -6L)), structure(list(Col1 = structure(c(1L, 4L, 6L, 5L, 2L, 3L), .Label = c("A", "W", "H", "M", "T", "U"), class = "factor"), Col2 = structure(c(1L, 2L, 3L, 2L, 4L, 5L), .Label = c("B", "C", "D", "S", "G"), class = "factor")), class = "data.frame", row.names = c(NA, -6L)))

library(purrr)
map_dfc(df, 1)
#> # A tibble: 6 x 3
#>   V1    V2    V3   
#>   <fct> <fct> <fct>
#> 1 A     A     A    
#> 2 B     M     M    
#> 3 C     N     U    
#> 4 D     P     T    
#> 5 E     E     W    
#> 6 F     H     H
map_dfc(df, "Col1")
#> # A tibble: 6 x 3
#>   V1    V2    V3   
#>   <fct> <fct> <fct>
#> 1 A     A     A    
#> 2 B     M     M    
#> 3 C     N     U    
#> 4 D     P     T    
#> 5 E     E     W    
#> 6 F     H     H

Created on 2018-09-19 by the reprex package (v0.2.0).

6 Comments

Gives the same error: Error in cbind_all(x) : Not compatible with STRSXP: [type=NULL]. and I also have purrr_0.2.5
Hmm, strange. I would investigate more but I think I have the expected behaviour, you are free to do so on your end? Can you do bind_cols(list(1:2, 3:4)), since, the dfc just calls dplyr::bind_cols anyway?
nope, both bind_cols(map(df, 1)) and bind_cols(list(1:2, 3:4)) give me the same error. My explanation that the elements need to be datafames come from Hadley's response in this issue: github.com/tidyverse/dplyr/issues/1389 not sure if it's by design or a bug. I would think that it is by design since Hadley has been a fan of type-stable functions. Not sure why it works for you.
Also looks like a bug from this issue: github.com/tidyverse/purrr/issues/395
OK, it turns out I had dplyr_0.7.4, which still had the issue. Updating to dplyr_0.7.6 solved the issue. Since bind_cols come from dplyr, updating purrr didn't help. Maybe you should make a note about this solution not working for dplyr versions before 0.7.6
|
1
res<-1:nrow(df[[1]][1])

for(i in 1:length(df)){
  print ( as.vector(df[[i]][1]))
  res<-cbind(res,as.data.frame(df[[i]][1]))
}
res$res<-NULL

So, the output is:

  Col1 Col1 Col1
1    A    A    A
2    B    M    M
3    C    N    U
4    D    P    T
5    E    E    W
6    F    H    H

Comments

0

Using dplyr

library(dplyr)
df %>% 
  sapply('[[',1) %>%
  as.data.frame
#returns
  V1 V2 V3
1  A  A  A
2  B  M  M
3  C  N  U
4  D  P  T
5  E  E  W
6  F  H  H

3 Comments

This is basically Rui's answer with pipes, there's nothing dplyr about it.
@avid_useR I see, should I remove it then?
Unless you have something else to show, I don't think this adds any value to Rui's answer

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.