Подтвердить что ты не робот

Объединение строк кадра данных

Я хотел бы взять кадр данных с символами и цифрами и объединить все элементы каждой строки в одну строку, которая будет храниться как один элемент в векторе. В качестве примера я создаю кадр данных с буквами и цифрами, а затем я хотел бы объединить первую строку с помощью функции вставки и, надеюсь, вернуть значение "A1"

df <- data.frame(letters = LETTERS[1:5], numbers = 1:5)
df

##   letters numbers
## 1       A       1
## 2       B       2
## 3       C       3
## 4       D       4
## 5       E       5

paste(df[1,], sep =".")
## [1] "1" "1"

Таким образом, вставка преобразует каждый элемент строки в целое число, соответствующее "индексу соответствующего уровня", как если бы оно было фактором, и оно удерживает его вектором длины два. (Я знаю/верю, что факторы, которые принуждаются быть персонажами, ведут себя таким образом, но поскольку R не хранит df [1,] как фактор вообще (проверено is.factor(), я не могу проверить, что это на самом деле является индексом для уровня)

is.factor(df[1,])
## [1] FALSE
is.vector(df[1,])
## [1] FALSE

Итак, если это не вектор, то имеет смысл, что он ведет себя странно, но я не могу принудить его к вектору

> is.vector(as.vector(df[1,]))
[1] FALSE

Использование as.character, похоже, не помогло в моих попытках

Может ли кто-нибудь объяснить это поведение?

4b9b3361

Ответ 1

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

df <- data.frame(letters = LETTERS[1:5], numbers = 1:5, stringsAsFactors=FALSE)
paste(df$letters, df$numbers, sep=""))

## [1] "A1" "B2" "C3" "D4" "E5"

Вы можете изменить df$letters на символ, используя df$letters <- as.character(df$letters), если вы не хотите использовать аргумент stringsAsFactors.

Но предположим, что не то, что ты хочешь. Предположим, у вас есть сотни столбцов, и вы хотите вставить их все вместе. Мы можем сделать это и с вашим минимальным примером:

df_args <- c(df, sep="")
do.call(paste, df_args)

## [1] "A1" "B2" "C3" "D4" "E5"

EDIT: Альтернативный метод и пояснение:

Я понял, что проблема, с которой вы сталкиваетесь, - это комбинация того факта, что вы используете фактор и используете вместо collapse аргумент sep (как подбирал @adibender). Разница в том, что sep дает разделитель между двумя отдельными векторами, а collapse дает разделители внутри вектора. Когда вы используете df[1,], вы указываете один вектор на paste и, следовательно, вы должны использовать аргумент collapse. Используя вашу идею получения каждой строки и конкатенирования, следующая строка кода будет делать именно то, что вы хотите:

apply(df, 1, paste, collapse="")

Хорошо, теперь для объяснений:

Почему as.list не работает?

as.list преобразует объект в список. Так оно и работает. Он преобразует ваш файл данных в список и затем игнорирует аргумент sep="". c объединяет объекты вместе. Технически, dataframe - это просто список, в котором каждый столбец является элементом, и все элементы должны иметь одинаковую длину. Поэтому, когда я объединяю его с sep="", он просто становится регулярным списком с столбцами элемента данных в качестве элементов.

Зачем использовать do.call?

do.call позволяет вам вызывать функцию, используя именованный список в качестве своих аргументов. Вы не можете просто выбросить список прямо в paste, потому что ему не нравятся данные. Он предназначен для конкатенации векторов. Поэтому помните, что dfargs - это список, содержащий вектор букв, вектор чисел и sep, который является вектором длины 1, содержащим только "". Когда я использую do.call, результирующая функция пасты по существу paste(letters, numbers, sep).
Но что, если мой исходный фреймворк имел столбцы "letters", "numbers", "squigs", "blargs", после чего я добавил разделитель, как раньше? Затем функция пасты через do.call будет выглядеть так:

paste(letters, numbers, squigs, blargs, sep)

Итак, вы видите, что он работает для любого количества столбцов.

Ответ 2

Это действительно немного странно, но это также должно произойти. Когда вы создаете data.frame, как и вы, столбец letters хранится как factor. Естественно, что факторы не имеют порядка, поэтому, когда as.numeric() применяется к коэффициенту, он возвращает порядок фактора. Например:

> df[, 1]
[1] A B C D E
Levels: A B C D E
> as.numeric(df[, 1])
[1] 1 2 3 4 5

A - это первый уровень фактора df[, 1], поэтому A преобразуется в значение 1, когда применяется as.numeric. Это происходит, когда вы вызываете paste(df[1, ]). Поскольку столбцы 1 и 2 имеют разный класс, вставка сначала преобразует оба элемента строки 1 в числовые, а затем в символы.

Если вы хотите объединить оба столбца, сначала нужно преобразовать первую строку в символ:

df[, 1] <- as.character(df[, 1])
paste(df[1,], collapse = "")

Как отметил @sebastian-c, вы также можете использовать stringsAsFactors = FALSE при создании data.frame, тогда вы можете опустить шаг as.character().

Ответ 3

Для тех, кто использует библиотеку (tidyverse), вы можете просто использовать функцию объединения.

 new.df<-df%>%
 unite(together, letters, numbers, sep="")

Это даст вам новый столбец "вместе" с A1, B2 и т.д.

Ответ 4

если вы хотите начать с

df <- data.frame(letters = LETTERS[1:5], numbers = 1:5, stringsAsFactors=TRUE)

.. то нет общего правила о том, как df$letters будет интерпретироваться любой данной функцией. Это фактор для функций моделирования, характер для некоторых и целое для некоторых других. Даже такая же функция, как паста, может интерпретировать ее по-разному, в зависимости от того, как вы ее используете:

paste(df[1,], collapse="") # "11"
apply(df, 1, paste, collapse="") # "A1" "B2" "C3" "D4" "E5"

Никакой логики в нем, кроме того, что это, вероятно, будет иметь смысл, если вы знаете внутренности каждой функции.

Факторы, по-видимому, преобразуются в целые числа, когда аргумент преобразуется в вектор (как вы знаете, кадры данных представляют собой списки векторов равной длины, поэтому первая строка кадра данных также является списком, а когда она вынужден быть вектором, что-то вроде этого происходит:)

df[1,]
#    letters numbers
# 1       A       1
unlist(df[1,])
# letters numbers 
#  1       1 

Я не знаю, как apply достигает того, что он делает (т.е. факторы представлены символьными значениями). Если вам интересно, посмотрите на его исходный код. Однако может быть полезно знать, что вы можете доверять (в этом конкретном смысле) apply (в этом конкретном случае). В более общем смысле, полезно хранить каждую часть данных в разумном формате, который включает в себя сохранение строк в виде строк, т.е. С использованием stringsAsFactors=FALSE.

Btw, каждая вводная книга R должна иметь эту идею в субтитрах. Например, мой план выхода на пенсию состоит в том, чтобы написать "A (не так)" мягкое введение в дзэн промысла данных с помощью R, строкиAsFactors = FALSE way ".