Реструктуризация данных с использованием R

У меня есть набор данных (dat), который выглядит следующим образом:

 Person       IPaddress
36598035    222.999.22.99
36598035    222.999.22.99
36598035    222.999.22.99
36598035    222.999.22.99
36598035    222.999.22.99
36598035    444.666.44.66
37811171    111.88.111.88
37811171    111.88.111.88
37811171    111.88.111.88
37811171    111.88.111.88
37811171    111.88.111.88

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

Person        IPaddress      Number of Logins
36598035    222.999.22.99           6
37811171    111.88.111.88           5

Таким образом, вместо нескольких записей для одного и того же человека, для каждого человека есть только одна строка со счетчиком того, сколько раз они вошли в систему.

Кроме того, в моем примере вы заметите, что человек 36598035 вошел под более чем одним IP-адресом. Когда это происходит, я хочу, чтобы IP-адрес в последнем наборе данных отражал IP-адрес режима - другими словами, IP-адрес, под которым человек входил в систему наиболее часто.

3 ответа

Решение

Вот один из подходов.

library(dplyr)

mydf %>%
    group_by(Person, IPaddress) %>% # For each combination of person and IPaddress
    summarize(freq = n()) %>% # Get total number of log-in
    arrange(Person, desc(freq)) %>% # The most frequent IP address is in the 1st row for each user
    group_by(Person) %>% # For each user
    mutate(total = sum(freq)) %>% # Get total number of log-in
    select(-freq) %>% # Remove count
    do(head(.,1)) # Take the first row for each user

#    Person     IPaddress total
#1 36598035 222.999.22.99     6
#2 37811171 111.88.111.88     5

ОБНОВИТЬ

dplyr 0,3 сейчас нет. Таким образом, вы можете сделать следующее. На одну строку короче, используя count, Я также использовал slice как рекомендуется @aosmith.

mydf %>%
    count(Person, IPaddress) %>%
    arrange(Person, desc(n)) %>%
    group_by(Person) %>%
    mutate(total = sum(n)) %>%
    select(-n) %>%
    slice(1)

Ты можешь использовать data.table для краткого решения:

library(data.table)
setDT(dat)
dat[, list(IPaddress=names(which.max(table(IPaddress))),
           Logins=.N), 
    by=Person]

Пытаться:

ddf
     Person     IPaddress
1  36598035 222.999.22.99
2  36598035 222.999.22.99
3  36598035 222.999.22.99
4  36598035 222.999.22.99
5  36598035 222.999.22.99
6  36598035 444.666.44.66
7  37811171 111.88.111.88
8  37811171 111.88.111.88
9  37811171 111.88.111.88
10 37811171 111.88.111.88
11 37811171 111.88.111.88

dd1 = data.table(with(ddf, table(Person, IPaddress)))[rev(order(N))][!duplicated(Person)]
dd1
     Person     IPaddress N
1: 36598035 222.999.22.99 5
2: 37811171 111.88.111.88 5

dd1$all_login_count = data.table(with(ddf, table(Person)))$V1
dd1
     Person     IPaddress N all_login_count
1: 36598035 222.999.22.99 5               6
2: 37811171 111.88.111.88 5               5
Другие вопросы по тегам