Почему я получаю X. в именах столбцов при чтении фрейма данных?

Я задал вопрос , и я думал, что ответ решил мою проблему, но я снова столкнулся с проблемой, и решение не сработало для меня.

Я импортирую CSV:

orders <- read.csv("<file_location>", sep=",", header=T, check.names = FALSE)

Вот структура фрейма данных:

str(orders)

'data.frame':   3331575 obs. of  2 variables:
 $ OrderID  : num  -2034590217 -2034590216 -2031892773 -2031892767 -2021008573 ...
 $ OrderDate: Factor w/ 402 levels "2010-10-01","2010-10-04",..: 263 263 269 268 301 300 300 300 300 300 ...

Если я запускаю команду length для первого столбца OrderID, я получаю следующее:

length(orders$OrderID)
[1] 0

Если я запускаю length в OrderDate, он возвращается правильно:

length(orders$OrderDate)
[1] 3331575

Это копирование/вставка head из CSV.

OrderID,OrderDate
-2034590217,2011-10-14
-2034590216,2011-10-14
-2031892773,2011-10-24
-2031892767,2011-10-21
-2021008573,2011-12-08
-2021008572,2011-12-07
-2021008571,2011-12-07
-2021008570,2011-12-07
-2021008569,2011-12-07

Теперь, если я повторно запущу read.csv, но уберу опцию check.names, первый столбец dataframe теперь будет иметь X. в начале имени.

orders2 <- read.csv("<file_location>", sep=",", header=T)

str(orders2)

'data.frame':   3331575 obs. of  2 variables:
 $ X.OrderID: num  -2034590217 -2034590216 -2031892773 -2031892767 -2021008573 ...
 $ OrderDate: Factor w/ 402 levels "2010-10-01","2010-10-04",..: 263 263 269 268 301 300 300 300 300 300 ...

length(orders$X.OrderID)
[1] 3331575

Это работает правильно.

Мой вопрос: почему R добавляет X в начало имени первого столбца? Как видно из CSV-файла, специальных символов нет. Это должна быть простая нагрузка. Добавление check.names, в то время как будет импортировано имя из CSV, приведет к тому, что данные не будут правильно загружаться для выполнения анализа.

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

Примечание: я понимаю, что это второстепенное - меня просто больше расстраивает тот факт, что я думаю, что загружаю правильно, но не получаю ожидаемого результата. Я мог бы переименовать столбец, используя colnames(orders)[1] <- "OrderID", но все же хочу знать, почему он загружается неправильно.


person mikebmassey    schedule 04.05.2012    source источник
comment
Можете ли вы вырезать и вставить следующие выходные данные: head(orders) и head(orders2)?   -  person Tyler Rinker    schedule 04.05.2012
comment
Мне больше любопытно увидеть настоящий необработанный CSV-файл. Можете ли вы опубликовать его где-нибудь и предоставить ссылку, чтобы мы могли загрузить его и попытаться воспроизвести это поведение. Какова бы ни была проблема, я думаю, что ответ кроется в точной структуре и содержимом файла.   -  person joran    schedule 04.05.2012
comment
Я не получаю str заказов, но затем length(orders$OrderID) [1]0   -  person Tyler Rinker    schedule 04.05.2012
comment
Я с @joran; Я предполагаю, что в начале файла есть невидимый символ, который вставляется в имя столбца (с check.names=FALSE) или вызывает изменение имени (с check.names=TRUE). К сожалению, вырезка из CSV, вероятно, этого не покажет. Что дает dput(names(orders)[1])? Кроме того, если length(orders[[1]]) дает правильное значение, то вы знаете, что оно содержится в имени.   -  person Brian Diggs    schedule 04.05.2012


Ответы (5)


read.csv() — это оболочка более общей функции read.table(). Эта последняя функция имеет аргумент check.names, который задокументирован как:

check.names: logical.  If ‘TRUE’ then the names of the variables in the
         data frame are checked to ensure that they are syntactically
         valid variable names.  If necessary they are adjusted (by
         ‘make.names’) so that they are, and also to ensure that there
         are no duplicates.

Если ваш заголовок содержит метки, которые синтаксически недействительны, то make.names() заменит их допустимым именем на основе недопустимого имени, удалив недопустимые символы и, возможно, добавив X:

R> make.names("$Foo")
[1] "X.Foo"

Это задокументировано в ?make.names:

Details:

    A syntactically valid name consists of letters, numbers and the
    dot or underline characters and starts with a letter or the dot
    not followed by a number.  Names such as ‘".2way"’ are not valid,
    and neither are the reserved words.

    The definition of a _letter_ depends on the current locale, but
    only ASCII digits are considered to be digits.

    The character ‘"X"’ is prepended if necessary.  All invalid
    characters are translated to ‘"."’.  A missing value is translated
    to ‘"NA"’.  Names which match R keywords have a dot appended to
    them.  Duplicated values are altered by ‘make.unique’.

Поведение, которое вы видите, полностью соответствует задокументированному способу read.table() загрузки ваших данных. Это предполагает, что у вас есть синтаксически недопустимые метки в строке заголовка вашего CSV-файла. Обратите внимание на пункт выше из ?make.names о том, что буква зависит от локали вашей системы; Файл CSV может содержать допустимый символ, который будет отображаться в вашем текстовом редакторе, но если R не работает в той же локали, например, этот символ может быть недопустимым?

Я бы посмотрел файл CSV и определил любые символы, отличные от ASCII, в строке заголовка; возможно, в строке заголовка также есть невидимые символы (или escape-последовательности; \t?). Между чтением файла с недопустимыми именами и его отображением в консоли может происходить многое, что может маскировать недопустимые символы, поэтому не принимайте тот факт, что он не показывает ничего неправильного без check.names как указание на то, что файл в порядке.

Также было бы полезно опубликовать вывод sessionInfo().

person Gavin Simpson    schedule 04.05.2012
comment
Хороший ответ, Гэвин +1 Интересно, есть ли пробел перед именем заголовка, поскольку make.names(" Foo") также создает "X.Foo". - person Tyler Rinker; 04.05.2012
comment
Можно ли вместо X использовать другой символ? - person Dan; 14.09.2016
comment
Очень упрощенное изложение этого идеального ответа: попробуйте добавить это в свой read.table(), если вы не хотите, чтобы R менял ваши имена: check.names=FALSE - person FatihSarigol; 07.10.2018

Я только что столкнулся с этой проблемой, и это было по простой причине. У меня были метки, которые начинались с цифры, и R добавлял X перед ними всеми. Я думаю, что R путают с числом в заголовке и применяют букву, чтобы отличать значения.

Итак, «3_in» стало «X3_in» и т. д. Я решил, переключив метку на «in_3», и проблемы были решены.

Я надеюсь, что это поможет кому-то.

person Matt Beam    schedule 29.01.2016
comment
Спасибо, Мэтт. Как вы систематически удаляли x. и добавить все столбцы с in_ ? - person Ryan Chase; 01.02.2016

Я столкнулся с похожей проблемой и хотел поделиться следующими строками кода, чтобы исправить имена столбцов. Конечно, не идеально, так как чистое программирование в форхенде было бы лучше, но может быть полезно в качестве отправной точки для кого-то как быстрый и грязный подход. (Я хотел бы добавить их в качестве комментария к вопросу Райана/ответу Гэвина, но моя репутация недостаточно высока, поэтому мне пришлось опубликовать дополнительный ответ - извините).

В моем случае несколько шагов записи и чтения данных создали один или несколько столбцов с именами «X», X.1»,..., содержащих содержимое в столбце X и номера строк в столбцах X.1,.... В моем случае содержимое столбца X следует использовать в качестве имен строк, а другие столбцы X.1,... следует удалить.

Correct_Colnames <- function(df) {

 delete.columns <- grep("(^X$)|(^X\\.)(\\d+)($)", colnames(df), perl=T)

  if (length(delete.columns) > 0) {

   row.names(df) <- as.character(df[, grep("^X$", colnames(df))])
   #other data types might apply than character or 
   #introduction of a new separate column might be suitable

   df <- df[,-delete.columns]

   colnames(df) <- gsub("^X", "",  colnames(df))
   #X might be replaced by different characters, instead of being deleted
  }

  return(df)
}
person Manuel Bickel    schedule 01.11.2016

Когда имена столбцов имеют неправильную форму, R помещает «X» в начале имени столбца во время импорта. Например, это обычно происходит, когда имена ваших столбцов начинаются с цифры или какого-либо пробела. Причина check.names = FALSE не произойдет - не будет "Х". Однако некоторые функции могут не работать, если имена столбцов начинаются с цифр или других специальных символов. Примером является функция rbind.fill.

Итак, после применения этой функции (с «исправленными именами столбцов») я использую эту простую вещь, чтобы избавиться от «X».

destroyX = function(es) {
  f = es
  for (col in c(1:ncol(f))){ #for each column in dataframe
    if (startsWith(colnames(f)[col], "X") == TRUE)  { #if starts with 'X' ..
      colnames(f)[col] <- substr(colnames(f)[col], 2, 100) #get rid of it
    }
  }
  assign(deparse(substitute(es)), f, inherits = TRUE) #assign corrected data to original name
}
person Dorregaray    schedule 20.11.2019

Я решил аналогичную проблему, включив row.names=FALSE в качестве аргумента в функцию write.csv. write.csv включал имена строк как безымянный столбец в CSV-файле, а read.csv называл этот столбец «X» при чтении CSV-файла.

person Tristan    schedule 15.06.2017