Поворот файла 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>