开发者

Create a Data Frame of Unequal Lengths

开发者 https://www.devze.com 2023-03-30 15:54 出处:网络
While data frame columns must have the same number rows, is there any way to create a data frame of unequal lengths. I\'m not interested in saving them as separate elements of a list because I often h

While data frame columns must have the same number rows, is there any way to create a data frame of unequal lengths. I'm not interested in saving them as separate elements of a list because I often have to to email people this info as a csv file, and this is easiest as a data frame.

x = c(rep("one",2))
y = c(rep("two",10))
z = c(rep("three",5))
cbind(x,y,z)

In the above code, the cbind() function just recycles the shorter columns so that they all have 10 elements in each column. How can I alter it just so that lengths are 2, 10, and 5.

I've done this in the past by doing the following, but it's inefficient.

  df = data.frame(one=c(rep("one",2),rep("",8)开发者_开发百科), 
           two=c(rep("two",10)), three=c(rep("three",5), rep("",5))) 


Sorry this isn't exactly what you asked, but I think there may be another way to get what you want.

First, if the vectors are different lengths, the data isn't really tabular, is it? How about just save it to different CSV files? You might also try ascii formats that allow storing multiple objects (json, XML).

If you feel the data really is tabular, you could pad on NAs:

> x = 1:5
> y = 1:12
> max.len = max(length(x), length(y))
> x = c(x, rep(NA, max.len - length(x)))
> y = c(y, rep(NA, max.len - length(y)))
> x
 [1]  1  2  3  4  5 NA NA NA NA NA NA NA
> y
 [1]  1  2  3  4  5  6  7  8  9 10 11 12

If you absolutely must make a data.frame with unequal columns you could subvert the check, at your own peril:

> x = 1:5
> y = 1:12
> df = list(x=x, y=y)
> attributes(df) = list(names = names(df),
    row.names=1:max(length(x), length(y)), class='data.frame')
> df
      x  y
1     1  1
2     2  2
3     3  3
4     4  4
5     5  5
6  <NA>  6
7  <NA>  7
 [ reached getOption("max.print") -- omitted 5 rows ]]
Warning message:
In format.data.frame(x, digits = digits, na.encode = FALSE) :
  corrupt data frame: columns will be truncated or padded with NAs


Another approach to the padding:

na.pad <- function(x,len){
    x[1:len]
}

makePaddedDataFrame <- function(l,...){
    maxlen <- max(sapply(l,length))
    data.frame(lapply(l,na.pad,len=maxlen),...)
}

x = c(rep("one",2))
y = c(rep("two",10))
z = c(rep("three",5))

makePaddedDataFrame(list(x=x,y=y,z=z))

The na.pad() function exploits the fact that R will automatically pad a vector with NAs if you try to index non-existent elements.

makePaddedDataFrame() just finds the longest one and pads the rest up to a matching length.


To amplify @goodside's answer, you can do something like

L <- list(x,y,z)
cfun <- function(L) {
  pad.na <- function(x,len) {
   c(x,rep(NA,len-length(x)))
  }
  maxlen <- max(sapply(L,length))
  do.call(data.frame,lapply(L,pad.na,len=maxlen))
}
cfun(L)


What you need is to pad NAs to the end of the vector to match the length of the longest vector, so you can do:

l <- tibble::lst(x, y, z)
data.frame(lapply(l, `length<-`, max(lengths(l))))

      x   y     z
1   one two three
2   one two three
3  <NA> two three
4  <NA> two three
5  <NA> two three
6  <NA> two  <NA>
7  <NA> two  <NA>
8  <NA> two  <NA>
9  <NA> two  <NA>
10 <NA> two  <NA>


We can create a data frame containing columns of unequal lengths by padding the columns with empty character "". The following code can be used to create a data frame with unequal lengths

The code first finds the maximum column length of a list object, l Next the columns are padded with "". This will cause each column of the list to have the same number of elements. The list is then converted to a data frame.

# The list column names
cols <- names(l)

# The maximum column length
max_len <- 0
for (col in cols){
    if (length(l[[col]]) > max_len)
        max_len <- length(l[[col]])
}

# Each column is padded
for (col in cols){
    l[[col]] <- c(l[[col]], rep("", max_len - length(l[[col]])))
}

# The list is converted to data frame
df <- as.data.frame(l)


Similar problem:

 coin <- c("Head", "Tail")
toss <- sample(coin, 50, replace=TRUE)

categorize <- function(x,len){
  count_heads <- 0
  count_tails <- 0
  tails <- as.character()
  heads <- as.character()
  for(i in 1:len){
    if(x[i] == "Head"){
      heads <- c(heads,x[i])
      count_heads <- count_heads + 1
    }else {
      tails <- c(tails,x[i])
      count_tails <- count_tails + 1
    }
  }
  if(count_heads > count_tails){
    head <- heads
    tail <- c(tails, rep(NA, (count_heads-count_tails)))
  } else {
    head <- c(heads, rep(NA,(count_tails-count_heads)))
    tail <- tails
  }
  data.frame(cbind("Heads"=head, "Tails"=tail))
}

categorize(toss,50)

Output: After the toss of the coin there will be 31 Head and 19 Tail. Then the rest of the tail will be filled with NA in order to make a data frame.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号