선 그래프에 선이 너무 많습니다. 더 나은 해결책이 있습니까?


30

시간이 지남에 따라 사용자 (이 경우 "좋아요")의 작업 수를 그래프로 표시하려고합니다.

그래서 저는 y 축으로 "행동 횟수"를 가지고 있고 x 축은 시간 (주)이며 각 줄은 한 명의 사용자를 나타냅니다.

내 문제는 약 100 명의 사용자에 대해이 데이터를보고 싶다는 것입니다. 선 그래프는 빠르게 100 개의 선으로 뒤죽박죽이됩니다. 이 정보를 표시하는 데 사용할 수있는 더 나은 그래프 유형이 있습니까? 아니면 개별 회선을 켜거나 끌 수 있는지 살펴 봐야합니까?

모든 데이터를 한 번에보고 싶지만, 많은 작업을 높은 정밀도로 식별 할 수있는 것은별로 중요하지 않습니다.

내가 왜 이러는거야

내 사용자 (최고 사용자)의 하위 집합의 경우 특정 날짜에 출시 된 응용 프로그램의 새 버전을 좋아하지 않을 수있는 사용자를 찾고 싶습니다. 개별 사용자의 작업 수가 크게 감소하고 있습니다.


5
선을 그리는 데 사용되는 알파를 변경하여 선을 반투명하게 만드는 것을 고려 했습니까?
Fomite

1
@EpiGrad 합리적인 제안이지만 실제로 내가 찾는 것을 더 쉽게 볼 수는 없습니다.
규제

1
@regulatethis 나는 ggplot2의 facet_wrap기능을 사용하여 차트 당 ~ 5 명의 사용자로 4 x ​​5 차트 (4 행, 5 열-원하는 종횡비에 따라 조정)의 블록을 만드는 "작은 배수"접근법을 제안합니다 . 그것은 충분히 명확해야하며 차트 당 최대 약 10 명의 사용자로 확장하여 4x5 플롯으로 200 명, 6x6 플롯으로 360 명을 수용 할 수 있습니다.
SlowLearner

답변:


31

(a) 사용자 간 변동, (b) 모든 사용자 간 변경에 대한 일반적인 반응, (c) 특정 기간에서 다음 기간까지의 일반적인 변동의 주요 영향을 제거하기위한 (표준) 예비 분석을 제안하고 싶습니다. .

이 작업을 수행하는 간단한 방법 (그러나 최선의 방법은 아님)은 데이터에서 "중간 연마"를 몇 번 반복하여 사용자 중앙값과 기간 중앙값을 소거 한 다음 시간에 따라 잔차를 부드럽게하는 것입니다. 크게 변하는 스무드를 식별하십시오. 그래픽에서 강조하려는 사용자입니다.

이것들은 카운트 데이터이기 때문에 제곱근을 사용하여 다시 표현하는 것이 좋습니다.

결과에 대한 예로, 주당 10-20 개의 작업을 수행하는 240 명의 사용자로 구성된 60 주 시뮬레이션 데이터 세트가 있습니다. 모든 사용자의 변경은 40 주 후에 발생했습니다.이 중 3 개는 변경에 부정적으로 응답하기 위해 "발표되었습니다". 왼쪽 그림은 원시 데이터를 보여줍니다. 시간별 사용자 별 행동 수 (사용자가 색상으로 구분). 질문에서 주장했듯이 엉망입니다. 오른쪽 그림은 반응이 좋지 않은 사용자를 자동으로 식별하고 강조 표시 하여이 EDA의 결과를 이전과 동일한 색상으로 표시합니다. 식별은 비록 다소 임시적 이지만 완전하고 정확합니다 (이 예에서는).

그림 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
100-200 명 이상의 사용자의 경우 허위 긍정을 피하기 위해 threshold약 로 증가 합니다 . 예를 들면 ,와 코드 시도 , (! 큰 비율이다), 그리고 . 2.5n.users <- 500n.outliers <- 100threshold <- 2.5
whuber

16

일반적으로 줄거리의 단일 패싯에서 2 개 또는 3 개 이상의 줄을 읽기가 어려워지기 시작합니다 (여전히 항상 그렇게하지만). 이것은 개념적으로 100면 패싯이 될 수있는 것을 가질 때해야 할 일에 대한 흥미로운 예입니다. 가능한 한 가지 방법은 100 개의 패싯을 모두 그리는 것이지만 페이지에서 한 번에 모든 패싯을 가져 오는 대신 애니메이션에서 한 번에 하나씩 보는 것입니다.

우리는 실제로이 기술을 작업에 사용했습니다. 원래는 이벤트의 배경 (새 데이터 시리즈의 시작)으로 60 가지 라인 플롯을 보여주는 애니메이션을 만든 다음 실제로 데이터의 일부 기능을 선택했습니다. 페이지 당 15 또는 30 개의 패싯이있는 패싯 플롯에는 표시되지 않았습니다.

@whuber에서 권장하는대로 사용자 및 일반적인 시간 효과를 제거하기 전에 원시 데이터를 표시하는 대체 방법이 있습니다. 이것은 그의 원시 데이터 표현에 대한 추가 대안으로 제시됩니다. 그런 다음 그가 제안한 것과 같은 라인을 따라 분석을 진행하는 것이 좋습니다.

이 문제를 해결하는 한 가지 방법은 100 (또는 @whuber의 예에서 240) 시계열 도표를 별도로 생성하여 애니메이션으로 묶는 것입니다. 아래 코드는 240 종류의 개별 이미지를 생성 한 다음 무료 영화 제작 소프트웨어를 사용하여 영화로 바꿀 수 있습니다. 불행히도 내가 이것을하고 수용 가능한 품질을 유지할 수있는 유일한 방법은 9MB 파일이지만, 인터넷을 통해 파일을 보낼 필요가없는 경우 문제가되지 않을 수 있으며 어쨌든 나는 더 많은 방법으로 그 주위에 방법이 있다고 확신합니다 애니메이션에 정통합니다. 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()그 안에 루프. NB, 당신은 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 사이트에 오신 것을 환영합니다. 그는 모든 데이터를보고 싶다고 말했습니다. 그러나 더 자세한 내용은 좋을 것입니다.
Peter Flom-Monica Monica 복원

+1-상자 그림을 시각화하는 대신 요약 통계를 선 그래프로 연결하는 것이 유용 할 수 있습니다. 아래의 예와 토론 은 이 답변을 참조하십시오 .
Andy W

7

확실한. 먼저 평균 작업 수를 기준으로 정렬하십시오. 그런 다음 각 사 분위수마다 하나씩 25 개의 선이있는 4 개의 그래프를 만듭니다. 즉, y 축을 축소 할 수 있지만 y 축 레이블을 명확하게 만들 수 있습니다. 25 개의 선으로 선 종류와 색상 및 기호를 플로팅하여 명확하게 표현할 수 있습니다.

그런 다음 단일 시간 축으로 그래프를 세로로 쌓습니다.

이것은 R 또는 SAS에서 매우 쉬울 것입니다 (적어도 SAS v. 9 인 경우).


2
+1-작은 배수 당 더 적은 라인을 제안합니다! 주제에 대한 내 관련 블로그 게시물 과 예제를 참조하십시오 . 정렬은 또한 좋은 아이디어이며, 다른 잠재적 인 것에는 기준선 또는 후속 조치의 값 또는 변화 측정 (예 : 양 또는 음의 기울기, 백분율 변화 등)이 포함될 수 있습니다.
Andy W

좋은! 커뮤니티 블로그 란 무엇입니까? 한 사람이 어떻게 접근하거나 쓸 수 있습니까?
Peter Flom-Monica Monica 복원

3
블로그에 참여하는 방법에 대한 자세한 내용 은 Skewed Distribution 대화방 에 들러 주십시오. 우리는 항상 지역 사회 구성원의 더 많은 기여를 위해 열려 있습니다.
Andy W

0

애니메이션을 통한 시간의 그래프 및 그래프 설정 도입에 대한 유형 옵션에 대한 옵션이 부족한 경우 작업 할 수있는 추가 차원을 제공하고 따라 가기 쉬운 방법으로 더 많은 정보를 표시 할 수 있기 때문에 . 주요 초점은 최종 사용자 경험에 있어야합니다.


Peter Ellis가 여기에 게시 한 솔루션 과 다른 점을 염두에 두셨습니까 ? 그렇다면 자세히 설명해 주시겠습니까?
whuber

0

개별 사용자의 변경에 가장 관심이있는 경우 Sparklines 모음 ( 예 : The Pudding의 예 )에 적합한 상황 일 수 있습니다 .

푸딩에서 나오는 스파크 라인의 예

이것들은 매우 상세하지만 축 레이블과 단위를 제거하여 한 번에 더 많은 차트를 표시 할 수 있습니다.

많은 데이터 도구가 내장되어 있지만 ( Microsoft Excel에는 sparklines가 있음 ) R로 빌드하기 위해 패키지를 가져와야한다고 생각합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.