Лінійний графік має занадто багато рядків, чи є краще рішення?


30

Я намагаюсь графікувати кількість дій користувачів (у даному випадку "лайків") протягом часу.

Отже, у мене є "Кількість дій" як вісь y, моя вісь x - час (тижні), і кожен рядок представляє одного користувача.

Моя проблема полягає в тому, що я хочу переглянути ці дані для набору з приблизно 100 користувачів. Лінійний графік швидко перетворюється в безлад з 100 рядків. Чи є кращий тип графіка, який я можу використовувати для відображення цієї інформації? Або я повинен переглядати можливість включення / вимкнення окремих ліній?

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

Чому я це роблю

Для підмножини моїх користувачів (топ-користувачів) я хочу з’ясувати, яким з них, можливо, не сподобалась нова версія програми, яка була розгорнута в певну дату. Я шукаю значного зниження кількості дій окремих користувачів.


5
Чи ви думали зробити лінії напівпрозорими, змінивши альфа, яка використовується для їх побудови?
Фоміт

1
@EpiGrad Розумна пропозиція, але це насправді не полегшило б бачити те, що я шукаю.
регулюйте це

1
@regulatethцький я б запропонував "невеликий множинний" підхід, використовуючи facet_wrapфункцію ggplot2 для створення блоку 4 х 5 діаграм (4 рядки, 5 стовпців - регулювання залежно від бажаного співвідношення сторін) з ~ 5 користувачами на графік. Це повинно бути достатньо зрозумілим, і ви можете масштабувати його до приблизно 10 користувачів на графік, що дає місце для 200 з діаграмою 4x5 або 360 з графіком 6x6.
SlowLearner

Відповіді:


31

Я хотів би запропонувати (стандартний) попередній аналіз для усунення основних наслідків (а) зміни серед користувачів, (б) типової відповіді всіх користувачів на зміну та (в) типової зміни від одного часового періоду до наступного .

Простий (але далеко не найкращий) спосіб зробити це - виконати кілька ітерацій "медіанного поліру" на даних, щоб змістити медіани користувачів та медіани часу, а потім згладити залишки з часом. Визначте гладкі, які сильно змінюються: це користувачі, яких ви хочете підкреслити у графіці.

Оскільки це дані про підрахунок, добре повторити їх за допомогою квадратного кореня.

Як приклад того, що може призвести, ось модельований на 60 тижнів набір даних 240 користувачів, які зазвичай проводять від 10 до 20 дій на тиждень. Зміни у всіх користувачів відбулися після 40 тижня. Трьом із них було сказано "негативно реагувати на зміну". Лівий сюжет відображає необроблені дані: підраховує кількість дій користувача (з розрізненням користувачів) за час. Як стверджується у питанні, це безлад. Правильний сюжет показує результати цього ЗНО - у тих же кольорах, що і раніше, з незвично чуйними користувачами, автоматично ідентифікованими та виділеними. Ідентифікація - хоча дещо спеціальна - є повною та правильною (у цьому прикладі).

Фігура 1

Ось Rкод, який видав ці дані та провів аналіз. Це можна було вдосконалити кількома способами, в тому числі

  • Використовуючи повний медіанний лак, щоб знайти залишки, а не лише одну ітерацію.

  • Згладжування залишків окремо до та після точки зміни.

  • Можливо, використовуючи складніший алгоритм виявлення зовнішньої форми. Поточний лише позначає всіх користувачів, діапазон залишків яких перевищує вдвічі більше середнього діапазону. Хоча і простий, він надійний і, здається, працює добре. (Значення, встановлене користувачем threshold, можна налаштувати, щоб зробити цю ідентифікацію більш або менш жорсткою.)

Проте тестування дозволяє припустити, що це рішення добре працює для широкого кола користувачів, від 12 до 240 або більше.

n.users <- 240        # Number of users (here limited to 657, the number of colors)
n.periods <- 60       # Number of time periods
i.break <- 40         # Period after which change occurs
n.outliers <- 3       # Number of greatly changed users
window <- 1/5         # Temporal smoothing window, fraction of total period
response.all <- 1.1   # Overall response to the change
threshold <- 2        # Outlier detection threshold

# Create a simulated dataset
set.seed(17)
base <- exp(rnorm(n.users, log(10), 1/2))
response <- c(rbeta(n.users - n.outliers, 9, 1),
              rbeta(n.outliers, 5, 45)) * response.all
actual <- cbind(base %o% rep(1, i.break), 
                base * response %o% rep(response.all, n.periods-i.break))
observed <- matrix(rpois(n.users * n.periods, actual), nrow=n.users)

# ---------------------------- The analysis begins here ----------------------------#
# Plot the raw data as lines
set.seed(17)
colors = sample(colors(), n.users) # (Use a different method when n.users > 657)
par(mfrow=c(1,2))
plot(c(1,n.periods), c(min(observed), max(observed)), type="n",
     xlab="Time period", ylab="Number of actions", main="Raw data")
i <- 0
apply(observed, 1, function(a) {i <<- i+1; lines(a, col=colors[i])})
abline(v = i.break, col="Gray")  # Mark the last period before a change

# Analyze the data by time period and user by sweeping out medians and smoothing
x <- sqrt(observed + 1/6)                        # Re-express the counts
mean.per.period <- apply(x, 2, median)
residuals <- sweep(x, 2, mean.per.period)
mean.per.user <- apply(residuals, 1, median)
residuals <- sweep(residuals, 1, mean.per.user)

smooth <- apply(residuals, 1, lowess, f=window)  # Smooth the residuals
smooth.y <- sapply(smooth, function(s) s$y)      # Extract the smoothed values
ends <- ceiling(window * n.periods / 4)          # Prepare to drop near-end values
range <- apply(smooth.y[-(1:ends), ], 2, function(x) max(x) - min(x))

# Mark the apparent outlying users
thick <- rep(1, n.users)
thick[outliers <- which(range >= threshold * median(range))] <- 3
type <- ifelse(thick==1, 3, 1)

cat(outliers) # Print the outlier identifiers (ideally, the last `n.outliers`)

# Plot the residuals
plot(c(1,n.periods), c(min(smooth.y), max(smooth.y)), type="n",
     xlab="Time period", ylab="Smoothed residual root", main="Residuals")
i <- 0
tmp <- lapply(smooth, 
       function(a) {i <<- i+1; lines(a, lwd=thick[i], lty=type[i], col=colors[i])})
abline(v = i.break, col="Gray")

3
threshold2.5n.users <- 500n.outliers <- 100threshold <- 2.5

16

Як правило, я знаходжу більше двох-трьох рядків на одній грані сюжету починає важко читати (хоча я все ще роблю це весь час). Отже, це цікавий приклад того, що робити, коли у вас є щось, що концептуально може бути стогранним сюжетом. Один із можливих способів - намалювати всі 100 граней, але замість того, щоб намагатись отримати їх усі на сторінці відразу, дивлячись на них по черзі в анімації.

Ми фактично використовували цю техніку в своїй роботі - ми спочатку створили анімацію, що показує 60 різних графіків ліній як фон для події (запуск нової серії даних), а потім з’ясували, що таким чином ми насправді підбирали деякі особливості даних які не було видно на гранованих ділянках з 15 або 30 гранями на сторінку.

Отже, ось альтернативний спосіб представлення необроблених даних, перш ніж почати видаляти користувача та типові часові ефекти, як рекомендує @whuber. Це подано лише як додаткову альтернативу його викладу необроблених даних - я повністю рекомендую вам потім продовжити аналіз за такими напрямками, як ті, які він пропонує.

Один із способів подолати цю проблему - створити сюжетні графіки 100 (або 240 на прикладі @ whuber) окремо та об'єднати їх в анімацію. Нижче наведений код створить 240 подібних зображень, і тоді ви можете використовувати безкоштовне програмне забезпечення для створення фільмів, щоб перетворити це на фільм. На жаль, єдиний спосіб, коли я міг би це зробити і зберегти прийнятну якість, - це файл розміром 9 Мб, але якщо вам не потрібно надсилати його через Інтернет, це може не бути проблемою, і все одно я впевнений, що є способи, як це зробити трохи більше анімація кмітливість. Пакет анімації в R може бути корисним тут (дозволяє зробити це все за викликом від R), але я просто спростив цю ілюстрацію.

Я зробив анімацію такою, що вона малює кожну лінію великим чорним кольором, а потім залишає бліду напівпрозору зелену тінь позаду, так що око отримує поступову картину накопичуваних даних. У цьому є як ризики, так і можливості - порядок додавання рядків залишить інше враження, тож слід подумати про те, щоб зробити його деяким сенсом.

Ось кілька знімків із фільму, в яких використовуються ті самі дані, що і @whuber: введіть тут опис зображення введіть тут опис зображення введіть тут опис зображення введіть тут опис зображення введіть тут опис зображення

# ---------------------------- Data generation - by @whuber ----------------------------#

n.users <- 240        # Number of users (here limited to 657, the number of colors)
n.periods <- 60       # Number of time periods
i.break <- 40         # Period after which change occurs
n.outliers <- 3       # Number of greatly changed users
window <- 1/5         # Temporal smoothing window, fraction of total period
response.all <- 1.1   # Overall response to the change
threshold <- 2        # Outlier detection threshold

# Create a simulated dataset
set.seed(17)
base <- exp(rnorm(n.users, log(10), 1/2))
response <- c(rbeta(n.users - n.outliers, 9, 1),
              rbeta(n.outliers, 5, 45)) * response.all
actual <- cbind(base %o% rep(1, i.break), 
                base * response %o% rep(response.all, n.periods-i.break))
observed <- matrix(rpois(n.users * n.periods, actual), nrow=n.users)

# ---------------------------- The analysis begins here ----------------------------#

# Alternative presentation of original data 
# 
setwd("eg animation")

for (i in 1:n.users){
    png(paste("line plot", i, ".png"),600,600,res=60)
    plot(c(1,n.periods), c(min(observed), max(observed)), 
        xlab="Time period", ylab="Number of actions", 
        main="Raw data", bty="l", type="n")
    if(i>1){apply(observed[1:i,], 1, function(a) {lines(a, col=rgb(0,100,0,50,maxColorValue=255))})}
    lines(observed[i,], col="black", lwd=2)
    abline(v = i.break, col="Gray")  # Mark the last period before a change
    text(1,60,i)
    dev.off()
}

##
# Then proceed to further analysis eg as set out by @whuber

+1, це гарна ідея. Ви також можете ініціювати нове вікно пристрою, використовуючи windows()або quartz(), а потім вклавши for()петлю всередині нього. Зверніть увагу: вам потрібно буде поставити Sys.sleep(1)внизу петлі, щоб ви могли бачити ітерації. Звичайно, ця стратегія насправді не зберігає файл фільму - потрібно просто запускати його кожен раз, коли ви хочете переглянути його знову.
gung - Відновіть Моніку

+1 Дуже гарна ідея - я спробую це наступним шансом, який отримаю. (GTW, Mathematica , наприклад, робить коротку роботу над створенням та збереженням таких анімацій.)
whuber

Дивовижна ідея - анімація за цими напрямками (або кодом і даними, які потрібно створити) зробить дуже сексуальне онлайн-додаток до публікації.
N Brouwer

7

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

day <- rep(1:10, 100)
likes <- rpois(1000, 10)
d <- data.frame(day, likes)
library(ggplot2)
qplot(x=day, y=likes, data=d, geom="boxplot", group=day)

введіть тут опис зображення

Для індивідуального аналізу я пропоную взяти невелику випадкову вибірку зі своїх даних та проаналізувати окремий часовий ряд.


1
Цікаве рішення, але те, що я дуже хочу бачити, як відбувається "зміна" на основі кожного користувача. Я хочу бачити коливання активності для окремих користувачів. Тому я вибрав лінію спочатку, але візуалізація зараз занадто захаращена.
регулюйте це

ну, це насправді залежить від того, які шаблони ви хочете бачити у своїх даних, можливо, якби ви могли сказати нам, що ви намагаєтесь дізнатись, ми могли б знайти рішення.
jem77bfp

Для підмножини моїх користувачів (топ-користувачів) я хочу з’ясувати, які з них, можливо, не сподобалися новій версії програми, яка була розгорнута в певну дату. Я шукаю значного зниження кількості дій окремих користувачів.
регулюйте це

Ласкаво просимо на сайт @ jem77bfp. він сказав, що хоче переглянути всі дані. Але було б непогано мати більше деталей, я згоден.
Пітер Флом - Відновіть Моніку

+1 - замість візуалізації графіків поля, хоча це може бути корисно для підключення підсумкової статистики в лінійних графіках. Дивіться цю мою відповідь для прикладу та обговорення нижче.
Енді Ш

7

Звичайно. По-перше, сортуйте за середньою кількістю дій. Потім складіть (скажімо) 4 графіки, кожен з яких має 25 рядків, по одному на кожен квартиль. Це означає, що ви можете стискати осі y (але чітко робити ярлик y осі). І, маючи 25 рядків, ви можете змінювати їх за типом і кольором рядка, можливо, символом графіки та отримувати деяку чіткість

Потім складіть графіки вертикально однією часовою віссю.

Це було б досить просто в R або SAS (принаймні, якщо у вас є v. 9 SAS).


2
+1 - Я б запропонував ще менше рядків на малий кратний! Дивіться мою пов’язану публікацію в блозі на цю тему та приклад. Сортування також є чудовою ідеєю, і інші потенційні можуть включати значення на початковій лінії чи подальші заходи, або заходи змін (наприклад, позитивний чи негативний нахил, відсоткові зміни тощо).
Енді Ш

Приємно! Що таке блог спільноти? Як один користувач отримує доступ до нього чи пише?
Пітер Флом - Відновіть Моніку

3
не соромтеся зупинитися в чаті кімнати розповсюдження Skewed, щоб дізнатися, як приєднатись до блогу. Ми завжди відкриті для більшого внеску членів громади.
Енді Ш

0

Я вважаю, що, коли ви закінчуєтесь, якщо параметри типу типу, якщо налаштування графіків та графіків, введення часу за допомогою анімації є найкращим способом відображення, оскільки це дає додатковий вимір для роботи та дозволяє відображати більше інформації у простому слідуванні способі . Ваша основна увага повинна бути зосереджена на користуванні кінцевим користувачем.


Ви мали на увазі щось, що відрізняється від рішення, яке Петро Елліс розмістив тут ? Якщо так, то можете, будь ласка, детальніше розглянути це?
whuber

0

Якщо вас найбільше цікавлять зміни для окремих користувачів, можливо, це хороша ситуація для колекції Sparklines (на зразок цього прикладу від The ​​Pudding ):

Приклад блискучих ліній від pudding.cool

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

У багатьох інструментах даних вони вбудовані ( Microsoft Excel має іскрові лінії ), але я здогадуюсь, що ви хочете взяти пакет, щоб створити їх у Р.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.