Žemiau rasite filmukus, kuriuose galima pamatyti kaip išsidėstę seimo nariai, kiekvienu laiko momentu.
Grafikuose $x$ ir $y$ ašys neturi realios prasmės, grafikų esmė yra atstumas tarp taškų. Kiekvienas taškas yra seimo narys, taško spalva nurodo kokiai frakcijai priklauso seimo narys, spalvų reikšmes galima pamatyti grafiko legendoje.
Kuo labiau taškai nutolę vienas nuo kito, tuo labiau išsiskiria seimo narių nuomonę.
Seimo narių pozicija paskaičiuota imant trijų mėnesių balsavimų duomenis. Toks trijų mėnesių langas slenkamas laike ir kiekvienas vaizdo įrašo kadras rodo sekančios dienos, trijų mėnesių pozicija. Galutiniame rezultate matyti kaip kinta seimo narių pozicija laike.
%matplotlib inline
import os
import numpy as np
import pandas as pd
from datetime import timedelta
from matplotlib import cm
from sklearn import decomposition, manifold
from matplotlib import pyplot as plt
from tqdm import tqdm
from matplotlib.ticker import NullFormatter
from math import ceil
from IPython.display import Image, YouTubeVideo
plt.style.use('default')
data = pd.read_csv('http://atviriduomenys.lt/data/lrs/balsavimai/balsavimai.csv.gz')
data.info(null_counts=True)
<class 'pandas.core.frame.DataFrame'> RangeIndex: 5530115 entries, 0 to 5530114 Data columns (total 9 columns): data 5530115 non-null object laikas 5530115 non-null object rezultatai.p_asm_id 5530115 non-null int64 rezultatai.vardas 5530115 non-null object rezultatai.frakcija 5499323 non-null object rezultatai.už 1982019 non-null object rezultatai.prieš 326457 non-null object rezultatai.susilaikė 499121 non-null object key 5530115 non-null object dtypes: int64(1), object(8) memory usage: 379.7+ MB
Pašalinam visus įrašus, kur Seimo narys nebalsavo. Mus domina tik tie įrašai, kur Seimo narys balsavo. Įtraukiant ir tuos, kurie nebalsavo, išsikraipys statistika, kadangi iš vis nebalsavosių yra didžioji dauguma.
data = data.dropna(how='all', subset=['rezultatai.už', 'rezultatai.prieš', 'rezultatai.susilaikė'])
Pasitikriname ar už/prieš/susilaikė laukų reikšmės yra tvarkingos, pavyzdžiui ar nėra +
(su tarpo simboliu) ir pan.
pd.concat([data['rezultatai.už'], data['rezultatai.prieš'], data['rezultatai.susilaikė']]).value_counts()
+ 2807597 dtype: int64
Matome, kad duomenys tvarkingi. Tokiu atveju verčiam už/prieš/susilaikė į skaitinę formą, nuo $-2$ (prieš) iki $2$ (už). Susilaikė verčiamas į $-1$.
data['vote'] = (
(data['rezultatai.už'] == '+') * 2 +
(data['rezultatai.susilaikė'] == '+') * -1 +
(data['rezultatai.prieš'] == '+') * -2
)
Kadangi vienas balsavimas identifikuojamas pagal balsavimo puslapio adresą, o adrese yra balsavimo id, ištraukiam balsavimo id į atskirą stulpelį, kad skaičiavimai veiktų greičiau.
data.iloc[0]['key']
'http://www.lrs.lt/sip/portal.show?p_r=15275&p_k=1&p_a=sale_bals&p_bals_id=-26066'
data['p_bals_id'] = data['key'].str.extract(r'p_bals_id=(-?\d+)', expand=False).astype(int)
Apjungiame datos ir laiko stulpelius į vieną stulpelį ir konvertuojame naują stulpelį į datos ir laiko tipą.
data['laikas'] = pd.to_datetime(data['data'] + ' ' + data['laikas'])
data.info(null_counts=True)
<class 'pandas.core.frame.DataFrame'> Int64Index: 2807597 entries, 0 to 5530114 Data columns (total 11 columns): data 2807597 non-null object laikas 2807597 non-null datetime64[ns] rezultatai.p_asm_id 2807597 non-null int64 rezultatai.vardas 2807597 non-null object rezultatai.frakcija 2799827 non-null object rezultatai.už 1982019 non-null object rezultatai.prieš 326457 non-null object rezultatai.susilaikė 499121 non-null object key 2807597 non-null object vote 2807597 non-null int64 p_bals_id 2807597 non-null int64 dtypes: datetime64[ns](1), int64(3), object(7) memory usage: 257.0+ MB
Žemiau yra bandymas vizualizuoti, kaip keičiasi partijų išsidėstymas pagal balsavimus laike. Vizualizacijai naudojamas trijų mėnesių langas, kuris slenkamas laike, kas savaitę. Iš kiekvieno lango generuojamas paveiksliukas, taikant dimensijų mažinimo algoritmą.
Išbandžiau keletą algoritmų tiek in decomposition, tiek iš manifold paketų, bet nei vienas iš jų netinka, tokio tipo vizualizacijai. Esminė problema, kad dimensijos yra klausimai, kurių reikšmė kinta, priklausomai nuo klausimo. Tai puikiai matosi ir vizualizacijoje, kadangi karts nuo karto vaizdas apsiverčia aukštyn kojom. Taip atsitinka todėl, kad frakcijos vieniems klausimams pritaria, kitiems ne. Nustatyti klausimų poliškumą nėra paprasta.
Bet kokiu atveju, šis tas gavosi.
def generate_frames(data, window, interval):
if os.path.exists('frames'):
!rm -r frames
!mkdir frames
since = data['laikas'].min()
total = ceil((data['laikas'].max() - window - data['laikas'].min()) / interval)
no_fraction = 'Be frakcijos'
alg = decomposition.PCA(n_components=2, random_state=0)
for i in tqdm(range(total)):
frame = data[(since < data['laikas']) & (data['laikas'] < (since + window))]
frame = frame.set_index(['rezultatai.frakcija', 'rezultatai.vardas', 'p_bals_id'], drop=True)['vote'].unstack().fillna(0)
frakcijos = list(frame.index.levels[0]) + [no_fraction]
result = pd.DataFrame(alg.fit_transform(frame), index=frame.index).reset_index()
fig, ax = plt.subplots(figsize=(16, 9))
result['frakcija'] = result['rezultatai.frakcija'].fillna(no_fraction)
for label, color in zip(frakcijos, cm.jet(np.linspace(0, 1, len(frakcijos)), alpha=.4)):
fraction = result[result['frakcija'] == label]
if len(fraction):
ax.scatter(fraction[0], fraction[1], s=100, color=color, label=label)
ax.set_title(since.date().strftime('%Y-%m-%d'))
ax.set_xlabel('')
ax.set_ylabel('')
ax.xaxis.set_major_formatter(NullFormatter())
ax.yaxis.set_major_formatter(NullFormatter())
ax.set_xlim(-40, 40)
ax.set_ylim(-30, 30)
plt.legend()
fig.savefig('frames/%04d.png' % i, dpi=120)
ax.cla()
plt.close(fig)
since += interval
generate_frames(
data=data.sort_values('laikas'),
window=timedelta(days=90),
interval=timedelta(days=1),
)
100%|██████████| 237/237 [01:50<00:00, 2.18it/s]
Galiausiai visus paveiksliukus suklijuojam į vientisą vaizdo failą.
Image('frames/0000.png')
!avconv -y -r 30 -i frames/%04d.png -b:v 1000k output.mp4
ffmpeg version 2.8.11-0ubuntu0.16.04.1 Copyright (c) 2000-2017 the FFmpeg developers built with gcc 5.4.0 (Ubuntu 5.4.0-6ubuntu1~16.04.4) 20160609 configuration: --prefix=/usr --extra-version=0ubuntu0.16.04.1 --build-suffix=-ffmpeg --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --cc=cc --cxx=g++ --enable-gpl --enable-shared --disable-stripping --disable-decoder=libopenjpeg --disable-decoder=libschroedinger --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libmodplug --enable-libmp3lame --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-librtmp --enable-libschroedinger --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxvid --enable-libzvbi --enable-openal --enable-opengl --enable-x11grab --enable-libdc1394 --enable-libiec61883 --enable-libzmq --enable-frei0r --enable-libx264 --enable-libopencv libavutil 54. 31.100 / 54. 31.100 libavcodec 56. 60.100 / 56. 60.100 libavformat 56. 40.101 / 56. 40.101 libavdevice 56. 4.100 / 56. 4.100 libavfilter 5. 40.101 / 5. 40.101 libavresample 2. 1. 0 / 2. 1. 0 libswscale 3. 1.101 / 3. 1.101 libswresample 1. 2.101 / 1. 2.101 libpostproc 53. 3.100 / 53. 3.100 Input #0, image2, from 'frames/%04d.png': Duration: 00:00:09.48, start: 0.000000, bitrate: N/A Stream #0:0: Video: png, rgba(pc), 1920x1080 [SAR 4724:4724 DAR 16:9], 25 fps, 25 tbr, 25 tbn, 25 tbc No pixel format specified, yuv444p for H.264 encoding chosen. Use -pix_fmt yuv420p for compatibility with outdated media players. [libx264 @ 0x180d7c0] using SAR=1/1 [libx264 @ 0x180d7c0] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 AVX2 LZCNT BMI2 [libx264 @ 0x180d7c0] profile High 4:4:4 Predictive, level 4.0, 4:4:4 8-bit [libx264 @ 0x180d7c0] 264 - core 148 r2643 5c65704 - H.264/MPEG-4 AVC codec - Copyleft 2003-2015 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=4 threads=6 lookahead_threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=abr mbtree=1 bitrate=1000 ratetol=1.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00 Output #0, mp4, to 'output.mp4': Metadata: encoder : Lavf56.40.101 Stream #0:0: Video: h264 (libx264) ([33][0][0][0] / 0x0021), yuv444p, 1920x1080 [SAR 1:1 DAR 16:9], q=-1--1, 1000 kb/s, 30 fps, 15360 tbn, 30 tbc Metadata: encoder : Lavc56.60.100 libx264 Stream mapping: Stream #0:0 -> #0:0 (png (native) -> h264 (libx264)) Press [q] to stop, [?] for help frame= 237 fps= 27 q=-1.0 Lsize= 978kB time=00:00:07.83 bitrate=1023.2kbits/s video:975kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.368449% [libx264 @ 0x180d7c0] frame I:2 Avg QP:26.25 size: 8067 [libx264 @ 0x180d7c0] frame P:61 Avg QP:29.02 size: 4689 [libx264 @ 0x180d7c0] frame B:174 Avg QP:36.54 size: 3996 [libx264 @ 0x180d7c0] consecutive B-frames: 2.1% 0.0% 0.0% 97.9% [libx264 @ 0x180d7c0] mb I I16..4: 14.1% 82.0% 4.0% [libx264 @ 0x180d7c0] mb P I16..4: 0.5% 4.2% 2.0% P16..4: 1.6% 0.4% 0.1% 0.0% 0.0% skip:91.3% [libx264 @ 0x180d7c0] mb B I16..4: 0.0% 0.8% 0.8% B16..8: 5.8% 0.6% 0.1% direct: 0.3% skip:91.6% L0:52.9% L1:46.2% BI: 1.0% [libx264 @ 0x180d7c0] final ratefactor: 29.92 [libx264 @ 0x180d7c0] 8x8 transform intra:62.6% inter:66.0% [libx264 @ 0x180d7c0] coded y,u,v intra: 20.0% 18.6% 15.4% inter: 0.7% 0.8% 0.7% [libx264 @ 0x180d7c0] i16 v,h,dc,p: 71% 26% 2% 1% [libx264 @ 0x180d7c0] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 19% 9% 59% 2% 2% 2% 2% 2% 2% [libx264 @ 0x180d7c0] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 22% 16% 33% 5% 5% 5% 5% 4% 3% [libx264 @ 0x180d7c0] Weighted P-Frames: Y:0.0% UV:0.0% [libx264 @ 0x180d7c0] ref P L0: 44.1% 6.0% 31.2% 18.7% [libx264 @ 0x180d7c0] ref B L0: 75.1% 18.7% 6.2% [libx264 @ 0x180d7c0] ref B L1: 90.0% 10.0% [libx264 @ 0x180d7c0] kb/s:1010.16
YouTubeVideo('Xz466FWNgMY')
Kad vizualizacijos paveiksliukas būtų stabilus, bandome įtraukti tik tuos klausimus, kurių rezultatas buvo „už“.
data = pd.merge(
data,
data.groupby('p_bals_id').agg({'vote': sum}).rename(columns={'vote': 'result'}),
how='left', left_on='p_bals_id', right_index=True,
)
generate_frames(
data=data[data['result'] > 0].sort_values('laikas'),
window=timedelta(days=90),
interval=timedelta(days=1),
)
100%|██████████| 7086/7086 [54:49<00:00, 1.86it/s]
Image('frames/0000.png')
!avconv -y -r 30 -i frames/%04d.png output_aye.mp4
ffmpeg version 2.8.11-0ubuntu0.16.04.1 Copyright (c) 2000-2017 the FFmpeg developers built with gcc 5.4.0 (Ubuntu 5.4.0-6ubuntu1~16.04.4) 20160609 configuration: --prefix=/usr --extra-version=0ubuntu0.16.04.1 --build-suffix=-ffmpeg --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --cc=cc --cxx=g++ --enable-gpl --enable-shared --disable-stripping --disable-decoder=libopenjpeg --disable-decoder=libschroedinger --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libmodplug --enable-libmp3lame --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-librtmp --enable-libschroedinger --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxvid --enable-libzvbi --enable-openal --enable-opengl --enable-x11grab --enable-libdc1394 --enable-libiec61883 --enable-libzmq --enable-frei0r --enable-libx264 --enable-libopencv libavutil 54. 31.100 / 54. 31.100 libavcodec 56. 60.100 / 56. 60.100 libavformat 56. 40.101 / 56. 40.101 libavdevice 56. 4.100 / 56. 4.100 libavfilter 5. 40.101 / 5. 40.101 libavresample 2. 1. 0 / 2. 1. 0 libswscale 3. 1.101 / 3. 1.101 libswresample 1. 2.101 / 1. 2.101 libpostproc 53. 3.100 / 53. 3.100 Input #0, image2, from 'frames/%04d.png': Duration: 00:04:43.44, start: 0.000000, bitrate: N/A Stream #0:0: Video: png, rgba(pc), 1920x1080 [SAR 4724:4724 DAR 16:9], 25 fps, 25 tbr, 25 tbn, 25 tbc No pixel format specified, yuv444p for H.264 encoding chosen. Use -pix_fmt yuv420p for compatibility with outdated media players. [libx264 @ 0x16c7a60] using SAR=1/1 [libx264 @ 0x16c7a60] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 AVX2 LZCNT BMI2 [libx264 @ 0x16c7a60] profile High 4:4:4 Predictive, level 4.0, 4:4:4 8-bit [libx264 @ 0x16c7a60] 264 - core 148 r2643 5c65704 - H.264/MPEG-4 AVC codec - Copyleft 2003-2015 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=4 threads=6 lookahead_threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00 Output #0, mp4, to 'output_aye.mp4': Metadata: encoder : Lavf56.40.101 Stream #0:0: Video: h264 (libx264) ([33][0][0][0] / 0x0021), yuv444p, 1920x1080 [SAR 1:1 DAR 16:9], q=-1--1, 30 fps, 15360 tbn, 30 tbc Metadata: encoder : Lavc56.60.100 libx264 Stream mapping: Stream #0:0 -> #0:0 (png (native) -> h264 (libx264)) Press [q] to stop, [?] for help frame= 7086 fps= 28 q=-1.0 Lsize= 16256kB time=00:03:56.13 bitrate= 563.9kbits/s video:16172kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.520091% [libx264 @ 0x16c7a60] frame I:29 Avg QP:16.28 size: 19498 [libx264 @ 0x16c7a60] frame P:1825 Avg QP:17.46 size: 4965 [libx264 @ 0x16c7a60] frame B:5232 Avg QP:29.32 size: 1325 [libx264 @ 0x16c7a60] consecutive B-frames: 1.4% 0.2% 0.5% 97.9% [libx264 @ 0x16c7a60] mb I I16..4: 22.3% 71.9% 5.8% [libx264 @ 0x16c7a60] mb P I16..4: 0.5% 0.9% 0.9% P16..4: 1.4% 0.8% 0.4% 0.0% 0.0% skip:95.2% [libx264 @ 0x16c7a60] mb B I16..4: 0.0% 0.1% 0.1% B16..8: 2.5% 0.5% 0.1% direct: 0.0% skip:96.7% L0:50.9% L1:48.0% BI: 1.1% [libx264 @ 0x16c7a60] 8x8 transform intra:52.3% inter:35.3% [libx264 @ 0x16c7a60] coded y,u,v intra: 19.0% 15.8% 13.8% inter: 0.3% 0.2% 0.2% [libx264 @ 0x16c7a60] i16 v,h,dc,p: 84% 14% 2% 0% [libx264 @ 0x16c7a60] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 20% 5% 73% 0% 0% 0% 0% 0% 0% [libx264 @ 0x16c7a60] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 21% 15% 31% 5% 6% 6% 6% 5% 5% [libx264 @ 0x16c7a60] Weighted P-Frames: Y:0.0% UV:0.0% [libx264 @ 0x16c7a60] ref P L0: 59.3% 5.7% 21.7% 13.3% [libx264 @ 0x16c7a60] ref B L0: 82.2% 14.6% 3.1% [libx264 @ 0x16c7a60] ref B L1: 93.7% 6.3% [libx264 @ 0x16c7a60] kb/s:560.85
YouTubeVideo('jXSnkhtvLYw')