Grafik garis memiliki terlalu banyak garis, apakah ada solusi yang lebih baik?

31

Saya mencoba membuat grafik jumlah tindakan oleh pengguna (dalam hal ini, "suka") dari waktu ke waktu.

Jadi saya memiliki "Jumlah tindakan" sebagai sumbu y, sumbu x adalah waktu (minggu), dan setiap baris mewakili satu pengguna.

Masalah saya adalah saya ingin melihat data ini untuk sekitar 100 pengguna. Grafik garis dengan cepat menjadi berantakan campur aduk dengan 100 baris. Apakah ada jenis grafik yang lebih baik yang dapat saya gunakan untuk menampilkan informasi ini? Atau haruskah saya melihat mampu mengaktifkan / menonaktifkan jalur individual?

Saya ingin melihat semua data sekaligus, tetapi bisa membedakan jumlah tindakan dengan presisi tinggi tidak terlalu penting.

Kenapa saya melakukan ini

Untuk sebagian pengguna saya (pengguna teratas), saya ingin mencari tahu yang mana yang mungkin tidak menyukai versi baru dari aplikasi yang diluncurkan pada tanggal tertentu. Saya mencari penurunan signifikan dalam jumlah tindakan oleh pengguna individu.

mengatur ini
sumber
5
Sudahkah Anda mempertimbangkan membuat garis semi-transparan dengan mengubah alfa yang digunakan untuk merencanakannya?
Fomite
1
@EpiGrad Saran yang masuk akal tapi itu tidak akan membuatnya lebih mudah untuk melihat apa yang saya cari.
mengatur ini
1
@regulatini saya akan menyarankan pendekatan "beberapa kecil" menggunakan facet_wrapfungsi ggplot2 untuk membuat blok grafik 4 x 5 (4 baris, 5 kolom - sesuaikan tergantung pada rasio aspek yang diinginkan) dengan ~ 5 pengguna per grafik. Itu harus cukup jelas dan Anda bisa meningkatkannya menjadi sekitar 10 pengguna per bagan, memberi ruang bagi 200 dengan plot 4x5 atau 360 dengan plot 6x6.
SlowLearner

Jawaban:

31

Saya ingin menyarankan analisis awal (standar) untuk menghapus efek utama dari (a) variasi di antara pengguna, (b) respons khas di antara semua pengguna terhadap perubahan, dan (c) variasi khas dari satu periode waktu ke periode berikutnya .

Cara sederhana (tetapi tidak berarti yang terbaik) untuk melakukan ini adalah dengan melakukan beberapa iterasi "median polesan" pada data untuk menyapu rata-rata median pengguna dan median periode waktu, kemudian menghaluskan residu dari waktu ke waktu. Identifikasi smooths yang banyak berubah: mereka adalah pengguna yang ingin Anda tekankan dalam grafik.

Karena ini adalah data jumlah, ide yang bagus untuk mengekspresikannya kembali menggunakan akar kuadrat.

Sebagai contoh dari apa yang dapat terjadi, berikut ini adalah dataset 60 minggu yang disimulasikan dari 240 pengguna yang biasanya melakukan 10 hingga 20 tindakan per minggu. Perubahan dalam semua pengguna terjadi setelah minggu ke-40. Tiga di antaranya "diberitahu" untuk merespons negatif terhadap perubahan tersebut. Plot kiri menunjukkan data mentah: jumlah tindakan oleh pengguna (dengan pengguna dibedakan berdasarkan warna) dari waktu ke waktu. Seperti ditegaskan dalam pertanyaan, itu berantakan. Plot yang tepat menunjukkan hasil EDA ini - dengan warna yang sama seperti sebelumnya - dengan pengguna yang luar biasa responsif secara otomatis diidentifikasi dan disorot. Identifikasi - meskipun agak ad hoc - lengkap dan benar (dalam contoh ini).

Gambar 1

Berikut adalah Rkode yang menghasilkan data ini dan melakukan analisis. Ini dapat ditingkatkan dalam beberapa cara, termasuk

  • Gunakan semir penuh untuk menemukan residu, bukan hanya satu iterasi.

  • Menghaluskan residunya secara terpisah sebelum dan sesudah titik perubahan.

  • Mungkin menggunakan algoritma pendeteksian pencilan yang lebih canggih. Yang saat ini hanya menandai semua pengguna yang rentang residunya lebih dari dua kali rentang median. Meskipun sederhana, itu kuat dan tampaknya berfungsi dengan baik. (Nilai yang thresholddapat diatur pengguna ,, dapat disesuaikan untuk membuat identifikasi ini lebih atau kurang ketat.)

Namun pengujian menyarankan solusi ini bekerja dengan baik untuk berbagai jumlah pengguna, 12 - 240 atau lebih.

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")
whuber
sumber
3
threshold2.5n.users <- 500n.outliers <- 100threshold <- 2.5
16

Secara umum saya menemukan lebih dari dua atau tiga baris pada satu sisi plot mulai sulit dibaca (walaupun saya masih melakukannya sepanjang waktu). Jadi ini adalah contoh menarik tentang apa yang harus dilakukan ketika Anda memiliki sesuatu yang secara konseptual bisa menjadi plot 100 faset. Salah satu cara yang mungkin adalah menggambar semua 100 aspek tetapi alih-alih mencoba untuk mendapatkan semuanya pada halaman sekaligus, melihatnya satu per satu dalam sebuah animasi.

Kami sebenarnya menggunakan teknik ini di pekerjaan saya - kami awalnya membuat animasi yang menampilkan 60 plot garis berbeda sebagai latar belakang untuk suatu acara (peluncuran seri data baru), kemudian menemukan bahwa dengan melakukan itu kami benar-benar mengambil beberapa fitur data. yang belum pernah terlihat dalam bidang faceted dengan 15 atau 30 aspek per halaman.

Jadi di sini adalah cara alternatif untuk menyajikan data mentah, sebelum Anda mulai menghapus pengguna dan efek waktu yang khas seperti yang direkomendasikan oleh @whuber. Ini disajikan hanya sebagai alternatif tambahan untuk penyajiannya data mentah - Saya sepenuhnya menyarankan Anda kemudian melanjutkan dengan analisis seperti yang ia sarankan.

Salah satu cara untuk mengatasi masalah ini adalah dengan menghasilkan plot seri 100 (atau 240 dalam contoh @ whuber) secara terpisah dan menyatukannya menjadi sebuah animasi. Kode di bawah ini akan menghasilkan 240 gambar terpisah dari jenis ini dan kemudian Anda dapat menggunakan perangkat lunak pembuatan film gratis untuk mengubahnya menjadi film. Sayangnya satu-satunya cara saya bisa melakukan ini dan menjaga kualitas yang dapat diterima adalah file 9MB, tetapi jika Anda tidak perlu mengirimkannya di internet yang mungkin tidak menjadi masalah dan lagi pula saya yakin ada cara lain dengan sedikit lebih banyak cerdas animasi. Paket animasi dalam R dapat berguna di sini (memungkinkan Anda melakukan semuanya dengan panggilan dari R) tetapi saya tetap membuatnya sederhana untuk ilustrasi ini.

Saya telah membuat animasi sedemikian rupa sehingga menarik setiap garis dalam hitam pekat kemudian meninggalkan bayangan hijau semi-transparan pucat di belakang sehingga mata mendapatkan gambar bertahap dari data yang terakumulasi. Ada risiko dan peluang dalam hal ini - urutan penambahan garis akan meninggalkan kesan yang berbeda, jadi Anda harus mempertimbangkan untuk membuatnya bermakna dalam beberapa cara.

Berikut adalah beberapa stills dari film, yang menggunakan data yang sama yang dihasilkan @whuber: masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini

# ---------------------------- 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
Peter Ellis
sumber
+1, ini ide yang bagus. Anda juga dapat memulai jendela perangkat baru menggunakan windows()atau quartz(), dan kemudian meletakkan for()lingkaran Anda di dalamnya. NB, Anda harus meletakkan a Sys.sleep(1)di bagian bawah loop Anda sehingga Anda benar-benar dapat melihat iterasi. Tentu saja, strategi ini sebenarnya tidak menyimpan file film - Anda hanya perlu menjalankannya kembali setiap kali Anda ingin menontonnya lagi.
gung - Reinstate Monica
+1 Ide yang sangat bagus - Saya akan mencoba ini pada kesempatan berikutnya. (GTW, Mathematica , misalnya, membuat karya pendek untuk membuat dan menyimpan animasi semacam itu.)
whuber
Ide yang luar biasa - animasi sepanjang garis ini (atau kode dan data yang akan dihasilkan) akan membuat lampiran online yang sangat seksi untuk sebuah publikasi.
N Brouwer
7

Salah satu hal termudah adalah boxplot. Anda dapat segera melihat bagaimana median sampel Anda bergerak dan hari-hari apa yang memiliki outlier paling banyak.

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)

masukkan deskripsi gambar di sini

Untuk analisis individual, saya sarankan mengambil sampel acak kecil dari data Anda dan menganalisis deret waktu terpisah.

jem77bfp
sumber
1
Solusi yang menarik, tetapi apa yang benar-benar ingin saya lihat adalah "perubahan" berdasarkan per pengguna. Saya ingin melihat fluktuasi aktivitas untuk pengguna individu. Itu sebabnya saya memilih garis awalnya, tetapi visualisasi terlalu berantakan sekarang.
regulatethis ini
baik, itu benar-benar tergantung pada pola apa yang ingin Anda lihat dalam data Anda, mungkin jika Anda bisa memberi tahu kami apa yang Anda coba cari tahu, kami bisa menemukan solusi.
jem77bfp
Untuk sebagian pengguna saya (pengguna teratas), saya ingin mencari tahu yang mana yang mungkin tidak menyukai versi baru dari aplikasi yang diluncurkan pada tanggal tertentu. Saya mencari penurunan signifikan dalam jumlah tindakan oleh pengguna individu.
mengatur ini
Selamat datang di situs @ jem77bfp. dia bilang dia ingin melihat semua data. Tetapi akan menyenangkan untuk memiliki lebih banyak detail, saya setuju.
Peter Flom - Reinstate Monica
+1 - daripada memvisualisasikan plot kotak meskipun akan berguna untuk menghubungkan statistik ringkasan dalam grafik garis. Lihat jawaban saya ini untuk contoh dan diskusi di bawah ini.
Andy W
7

Yakin. Pertama, urutkan berdasarkan jumlah tindakan rata-rata. Kemudian buat (katakanlah) 4 grafik, masing-masing dengan 25 garis, satu untuk setiap kuartil. Itu berarti Anda dapat mengecilkan sumbu-y (tetapi memperjelas label sumbu y). Dan dengan 25 garis, Anda dapat memvariasikannya berdasarkan jenis dan warna garis dan mungkin memplot simbol dan mendapatkan kejelasan

Kemudian susun grafik secara vertikal dengan sumbu waktu tunggal.

Ini akan sangat mudah di R atau SAS (setidaknya jika Anda memiliki v. 9 dari SAS).

Peter Flom - Pasang kembali Monica
sumber
2
+1 - Saya menyarankan lebih sedikit baris per kelipatan kecil! Lihat posting blog terkait saya tentang subjek dan contoh. Penyortiran juga merupakan ide bagus, dan yang potensial lainnya dapat mencakup nilai pada awal atau tindak lanjut, atau ukuran perubahan (seperti kemiringan positif atau negatif, perubahan persen, dll).
Andy W
Bagus! Apa itu blog komunitas? Bagaimana seseorang mengakses atau menulis untuk itu?
Peter Flom - Reinstate Monica
3
silakan mampir ke ruang obrolan Distribusi Skewed untuk detail tentang cara bergabung dengan blog. Kami selalu terbuka untuk lebih banyak kontribusi dari anggota komunitas.
Andy W
0

Saya menemukan bahwa ketika Anda kehabisan jika opsi mengenai jenis jika grafik dan pengaturan grafik pengenalan waktu melalui animasi adalah cara terbaik untuk ditampilkan karena memberi Anda dimensi ekstra untuk bekerja dengan dan memungkinkan Anda untuk menampilkan lebih banyak informasi dengan cara yang mudah diikuti. . Fokus utama Anda harus pada pengalaman pengguna akhir.

DataDancer
sumber
Apakah Anda memiliki sesuatu dalam pikiran yang berbeda dari solusi yang telah diposting Peter Ellis di sini ? Jika demikian, bisakah Anda menjelaskannya?
whuber
0

Jika Anda paling tertarik dengan perubahan untuk pengguna individual, mungkin ini adalah situasi yang baik untuk koleksi Sparklines (seperti contoh ini dari The Pudding ):

Contoh grafik mini dari pudding.cool

Ini cukup detail, tetapi Anda bisa menampilkan lebih banyak grafik sekaligus dengan menghapus label dan unit sumbu.

Banyak alat data yang membuatnya ( Microsoft Excel memiliki grafik mini ), tapi saya kira Anda ingin menarik paket untuk membuatnya di R.

bryanbraun
sumber