Выберите только дату и связанную строку на основе условия из файла длинного формата - PullRequest
1 голос
/ 19 марта 2012

У меня есть CSV-файл, который можно импортировать в R. Это информационный фрейм с множеством столбцов в «длинной форме», то есть есть несколько записей для одного и того же идентификатора.Я воспроизводлю пример набора данных и результирующий набор данных, который я пытаюсь получить, используя только первые 5 столбцов (у меня на самом деле намного больше столбцов в моих реальных данных).Исходный набор данных может быть воспроизведен в R следующим образом:

df <- data.frame(id = c("id1","id1","id2","id2","id2","id2","id3","id3"), date = c("30/10/20010 from Steve.","30/16/2005 from Anna. 09/08/2008 from Steve. 09/10/2009 from Steve.","06/05/2004 from Allen.","08/09/2005 from Anna.","08/05/2008 from Allen. 30/10/2010 from Bobby.","14/03/2002 from Steve. 23/07/2003 from Anna.","08/08/2002 from Steve.", "08/08/2002 from Anna. 08/08/2002 from Steve."), v1 = c(1,NA,1,1,2,NA,1,2), v2 = c(2,NA,2,NA,NA,NA,2,NA), v3 = c(1,NA,NA,2,NA,1,1,NA), v4 = c("Y","N","N","Y","NA","NA","Y","Y"), v5 = c(0,0,NA,0,0,NA,0,NA))

идентификатор даты v1 v2 v3 v4 v5

1 id1 30/10/20010 от Стива.1 2 1 Y 0

2 id1 30/16/2005 от Анны.08.09.2008 от Стива.09.10.2009 от Стива.NA NA NA N 0

3 id2 06/05/2004 от Аллена.1 2 NA N NA

4 id2 08/09/2005 от Анны.1 NA 2 Y 0

5 id2 08/05/2008 от Аллена.30/10/2010 от Бобби.2 NA NA NA 0

6 id2 14/03/2002 от Стива.23/07/2003 от Анны.NA NA 1 NA NA

7 id3 08/08/2002 от Стива.1 2 1 Y 0

8 id3 08/08/2002 от Анны.08.08.2002 от Стива.2 NA NA Y NA

Я пытаюсь получить набор данных, в котором для каждого идентификатора выбирается только строка с самой поздней датой из столбца date, и если все даты совпадают,выберите строку с наименьшим числом NA (отсутствующих значений):

идентификатор даты v1 v2 v3 v4 v5

1 id1 30/10/20010 1 2 1 Y 0

5 id2 30/10/2010 2 NA NA NA 0

7 id3 08/08/2002 1 2 1 Y 0

Я думал о разбиении столбцовв R, используя «from» в качестве разделителя, но это никуда меня не приведет:

try<- strsplit(df$date, "from", fixed=TRUE)

Тогда я подумал, что может быть лучше выбрать даты в BASH: но это также не требуетменя где угодно:

grep "[0-9][0-9]\/[0-9][0-9]\/20[0-9][0-9]" file.csv | less -S

По сути, я заблудился в том, как к этому подойти.Я был бы ОЧЕНЬ благодарен, если бы кто-то мог предложить правильный подход, надеюсь, просто используя BASH или R?Спасибо!

1 Ответ

1 голос
/ 19 марта 2012

Вот скрипт, который работает с данными вашего примера

(после исправления двух дат: 30/10/20010 --> 30/10/2010 и 30/16/2005 --> 30/06/2005)

df <- data.frame(id = c("id1","id1","id2","id2","id2","id2","id3","id3"), date = c("30/10/2010 from Steve.","30/06/2005 from Anna. 09/08/2008 from Steve. 09/10/2009 from Steve.","06/05/2004 from Allen.","08/09/2005 from Anna.","08/05/2008 from Allen. 30/10/2010 from Bobby.","14/03/2002 from Steve. 23/07/2003 from Anna.","08/08/2002 from Steve.", "08/08/2002 from Anna. 08/08/2002 from Steve."), v1 = c(1,NA,1,1,2,NA,1,2), v2 = c(2,NA,2,NA,NA,NA,2,NA), v3 = c(1,NA,NA,2,NA,1,1,NA), v4 = c("Y","N","N","Y","NA","NA","Y","Y"), v5 = c(0,0,NA,0,0,NA,0,NA))

# Convert string to list of dates, extract maximum (earliest date)
df.dates <- sapply(as.character(df$date), function(x) strsplit(x, "\\."))
df.dates <- lapply(df.dates, function(x) as.Date(x, format='%d/%m/%Y'))
df.dates <- lapply(df.dates, max)

# Add to dataframe
df$latest <- unlist(df.dates)

# Count the number of NA values per row
df$naCount <- apply(df, 1, function(x) sum(is.na(x[3:7])))

# Split data and select either maximum (latest) date or minimal NA count
df.split <- split(df, df$id)

df.select <- lapply(df.split, function(x){

    # Select by given criterion
    if(length(unique(x$latest)) == 1){
        y <- x[which(min(x$naCount) == x$naCount),]
        }
    else{
        y <- x[which(max(x$latest) == x$latest),]
    }

    # Check if selection was successful
    if(nrow(y) != 1) cat('Warning: non-unique choice, returning more than one line')

    # Return result
    y
})

# Combine into output dataframe
df.select <- do.call(rbind, df.select)

Результат скрипта выглядит следующим образом:

> df.select

     id                                          date v1 v2 v3 v4 v5 latest naCount
id1 id1                        30/10/2010 from Steve.  1  2  1  Y  0  14912       0
id2 id2 08/05/2008 from Allen. 30/10/2010 from Bobby.  2 NA NA NA  0  14912       2
id3 id3                        08/08/2002 from Steve.  1  2  1  Y  0  11907       0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...