Поворот файла CSV с помощью R

У меня есть файл, который выглядит так:

                 type          created_at repository_name
1         IssuesEvent 2012-03-11 06:48:31       bootstrap
2         IssuesEvent 2012-03-11 06:48:31       bootstrap
3         IssuesEvent 2012-03-11 06:48:31       bootstrap
4         IssuesEvent 2012-03-11 06:52:50       bootstrap
5         IssuesEvent 2012-03-11 06:52:50       bootstrap
6         IssuesEvent 2012-03-11 06:52:50       bootstrap
7   IssueCommentEvent 2012-03-11 07:03:57       bootstrap
8   IssueCommentEvent 2012-03-11 07:03:57       bootstrap
9   IssueCommentEvent 2012-03-11 07:03:57       bootstrap
10        IssuesEvent 2012-03-11 07:03:58       bootstrap
11        IssuesEvent 2012-03-11 07:03:58       bootstrap
12        IssuesEvent 2012-03-11 07:03:58       bootstrap
13         WatchEvent 2012-03-11 07:15:44       bootstrap
14         WatchEvent 2012-03-11 07:15:44       bootstrap
15         WatchEvent 2012-03-11 07:15:44       bootstrap
16         WatchEvent 2012-03-11 07:18:45        hogan.js
17         WatchEvent 2012-03-11 07:18:45        hogan.js
18         WatchEvent 2012-03-11 07:18:45        hogan.js

Доступ к набору данных, с которым я работаю, можно найти на https://github.com/aronlindberg/VOSS-Sequencing-Toolkit/blob/master/twitter_exploratory_analysis/twitter_events_mini.csv.

Я хочу создать таблицу, в которой есть столбец для каждой записи в столбце "repository_name" (например, bootstrap, hogan.js). В этом столбце мне нужно, чтобы данные из столбца "тип", которые соответствуют этой записи (т. Е. Только строки из текущего столбца "тип", который также имеет значение "начальной загрузки" в текущем столбце "repository_name", должны попадать под новая колонка "начальной загрузки"). Следовательно:

  • Отметки времени предназначены только для упорядочивания и не требуют синхронизации по строке (фактически их можно удалить, поскольку данные уже отсортированы по отметкам времени).
  • Даже если "IssuesEvent" повторяется 10 раз, мне нужно сохранить все это, так как я буду выполнять анализ последовательности с использованием пакета R TraMineR
  • Колонны могут быть неравной длины
  • Нет связи между столбцами для разных репозиториев ("repository_name")

Другими словами, я хотел бы таблицу, которая выглядит примерно так:

     bootstrap            hogan.js
1    IssuesEvent          PushEvent
2    IssuesEvent          IssuesEvent
3    OssueCommentEvent    WatchEvent

Как я могу сделать это в R?

Некоторые из моих неудачных попыток с помощью пакета изменения формы можно найти по https://github.com/aronlindberg/VOSS-Sequencing-Toolkit/blob/master/twitter_exploratory_analysis/reshaping_bigqueries.R.

3 ответа

Решение

Ваши образцы данных:

data <- structure(list(type = structure(c(2L, 2L, 2L, 2L, 2L, 2L, 1L, 
1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L), .Label = c("IssueCommentEvent", 
"IssuesEvent", "WatchEvent"), class = "factor"), created_at = structure(c(1L, 
1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 4L, 4L, 4L, 5L, 5L, 5L, 6L, 6L, 
6L), .Label = c("2012-03-11 06:48:31", "2012-03-11 06:52:50", 
"2012-03-11 07:03:57", "2012-03-11 07:03:58", "2012-03-11 07:15:44", 
"2012-03-11 07:18:45"), class = "factor"), repository_name = structure(c(1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 
2L), .Label = c("bootstrap", "hogan.js"), class = "factor")), .Names = c("type", 
"created_at", "repository_name"), class = "data.frame", row.names = c(NA, 
-18L))

Я получаю из вашего ожидаемого вывода, что вы хотите только один type когда он появляется несколько раз для одного и того же created_at значение, другими словами, вы хотите удалить дубликаты:

data <- unique(data)

Затем, чтобы извлечь все type записей в repository_name в порядке их появления вы можете просто использовать:

data.split <- split(data$type, data$repository_name)
data.split
# $bootstrap
# [1] IssuesEvent       IssuesEvent       IssueCommentEvent
# [4] IssuesEvent       WatchEvent       
# Levels: IssueCommentEvent IssuesEvent WatchEvent
# 
# $hogan.js
# [1] WatchEvent
# Levels: IssueCommentEvent IssuesEvent WatchEvent

Он возвращает список, который является выбранной структурой данных R для коллекции векторов различной длины.

Изменить: Теперь, когда вы предоставили пример ваших выходных данных, стало более очевидно, что ваш ожидаемый результат действительно является data.frame. Вы можете преобразовать приведенный выше список в data.frame, дополненный NAс помощью следующей функции:

list.to.df <- function(arg.list) {
   max.len  <- max(sapply(arg.list, length))
   arg.list <- lapply(arg.list, `length<-`, max.len)
   as.data.frame(arg.list)
}

df.out <- list.to.df(data.split)
df.out
#           bootstrap   hogan.js
# 1       IssuesEvent WatchEvent
# 2       IssuesEvent       <NA>
# 3 IssueCommentEvent       <NA>
# 4       IssuesEvent       <NA>
# 5        WatchEvent       <NA>

Затем вы можете сохранить это в файл, используя

write.csv(df.out, file = "out.csv", quote = FALSE, na = "", row.names = FALSE)

чтобы получить точно такой же формат вывода, как тот, который вы опубликовали на github.

Я только что присоединился к stackru; надеюсь, мой ответ несколько полезен.

Под таблицей я предполагаю, что вы имеете в виду, что вам нужен фрейм данных. Однако кажется маловероятным, что столбцы будут иметь одинаковую длину, и похоже, что строки в любом случае не будут иметь большого значения. Может быть, список будет лучше?

Вот грязное решение:

names <- unique(olddataframe$repository_name)
results <- sapply(1:length(names), function(j){
    sapply(which(olddataframe$repository_name == names[j]), function(i){
        olddataframe$type[i]
   )
})
names(results) <- names
results

Используя @ Flodel's data объект, вы также можете попробовать aggregate(), но со многими типами событий это быстро станет нечитаемым:

aggregate(list(Type = unique(data)$type), 
          list(Repository = unique(data)$repository_name), 
          function(x) paste0(x))
#   Repository                                                                 Type
# 1  bootstrap IssuesEvent, IssuesEvent, IssueCommentEvent, IssuesEvent, WatchEvent
# 2   hogan.js                                                           WatchEvent

Вы также можете попробовать reshape() и подшучивать t() (транспонировать), как показано ниже.

temp = unique(data)
temp = reshape(temp, direction = "wide", 
               idvar="repository_name", timevar="created_at")
# If you want to keep the times, remove `row.names=NULL` below
temp1 = data.frame(t(temp[-1]), row.names=NULL)
names(temp1) = t(temp[1])
temp1
#           bootstrap   hogan.js
# 1       IssuesEvent       <NA>
# 2       IssuesEvent       <NA>
# 3 IssueCommentEvent       <NA>
# 4       IssuesEvent       <NA>
# 5        WatchEvent       <NA>
# 6              <NA> WatchEvent

Но я считаю, что все эти АН противны; Я бы сказал, что ответ @flodel является наиболее прямым и, вероятно, наиболее полезным в долгосрочной перспективе (то есть не зная точно, что вы хотите сделать, как только получите данные в этой форме).

Обновление (больше хитрости)

(На самом деле, это момент "ТАК идеально подходит для проволочек")

Мой окончательный (ужасно неэффективный) ответ заключается в следующем.

Продолжайте, как описано выше, но отбросьте материал даты / времени и преобразуйте факторы в символы.

# Using @flodel's data
temp1 = unique(data)[-2]
# Remove the factors
temp1[sapply(temp1, is.factor)] = lapply(temp1[sapply(temp1, is.factor)], 
                                         as.character)
# Split and unlist your data
temp2 = split(temp1[-c(2:3)], temp1$repository_name)
temp3 = sapply(temp2, as.vector)

rbind() а также cbind() будет "перерабатывать" объекты различной длины, чтобы сделать их одинаковой длины, но мы этого не хотим. Итак, нам нужно заставить R поверить, что длины одинаковы. Итак, узнайте максимальную длину. Пока мы на этом, извлеките очищенную версию имен в temp3 объект.

# What is the max number of rows we need?
LEN = max(sapply(temp3, length))
# What are the names we want for our columns?
NAMES = gsub(".type", "", names(temp3))

Теперь извлеките предметы из temp3 в рабочее пространство и убедитесь, что они имеют одинаковую длину.

# Use assign to unlist the vectors to the workspace
for (i in 1:length(temp3)) assign(NAMES[i], temp3[[i]])
# Make sure they have the same lengths
length(hogan.js) = LEN
length(bootstrap) = LEN

Наконец, используйте cbind() собрать ваши данные вместе.

# Use cbind to put these together
data.frame(cbind(bootstrap, hogan.js))
#           bootstrap   hogan.js
# 1       IssuesEvent WatchEvent
# 2       IssuesEvent       <NA>
# 3 IssueCommentEvent       <NA>
# 4       IssuesEvent       <NA>
# 5        WatchEvent       <NA>
Другие вопросы по тегам