joshdavham commited on
Commit
34cc53e
·
1 Parent(s): 38a1839

more modifications to source

Browse files
Files changed (1) hide show
  1. app.py +106 -58
app.py CHANGED
@@ -33,14 +33,14 @@ def load_dataframes():
33
  def get_grammar_table():
34
 
35
  data = {
36
- 'Complete Beginner': [0.02638719922016275 ,0.0192492959834, 0.00476028625918155, 0.2503071253071253],
37
- 'Beginner': [0.0473047304730473, 0.0266429840142095, 0.005813953488372, 0.2454068241469816],
38
- 'Intermediate': [0.06625719079578135, 0.03514773095199635, 0.0087719298245614, 0.23239271705403663],
39
- 'Advanced': [0.0766787658802177, 0.0373056994818652, 0.0108588351431391, 0.2237101220953131]
40
  }
41
  df = pd.DataFrame(data)
42
 
43
- row_labels = ['Median Perc. Subordinating Conjunctions', 'Median Perc. Adverbs', 'Median Perc. Determiners', 'Median Perc. Nouns']
44
  df.index = row_labels
45
 
46
  styled_df = df.style.set_table_styles(
@@ -164,8 +164,8 @@ def get_wpm_chart(show_medians=False):
164
  ),
165
  tooltip=[
166
  alt.Tooltip('wpm:Q', title='Words per minute:', bin=True),
 
167
  alt.Tooltip('level:N', title='Level:'),
168
- alt.Tooltip('count()', title='Video count:')
169
  ],
170
  opacity=alt.condition(selection, alt.value(0.75), alt.value(0.1)),
171
  strokeWidth=alt.condition(highlight, alt.value(2), alt.value(1))
@@ -285,10 +285,9 @@ def get_wpm_vs_sps_chart(interactive=False):
285
  ),
286
  tooltip=[
287
  alt.Tooltip('video:N', title='Video number:'),
288
- alt.Tooltip('level:N', title='Level:'),
289
  alt.Tooltip('wpm:Q', title='WPM:'),
290
  alt.Tooltip('sps:Q', title='SPS:'),
291
-
292
  ],
293
  opacity=alt.condition(selection, alt.value(1.0), alt.value(0.2)),
294
  ).properties(
@@ -336,7 +335,7 @@ def get_sentence_length_hist(show_medians=False):
336
  alt.X(
337
  'mean_sentence_length:Q',
338
  bin=alt.Bin(maxbins=30),
339
- title='Average sentence length',
340
  axis=alt.Axis(
341
  labelFontSize=14,
342
  titleFontSize=18,
@@ -379,8 +378,8 @@ def get_sentence_length_hist(show_medians=False):
379
  ),
380
  tooltip=[
381
  alt.Tooltip('mean_sentence_length:Q', title='Average sentence length:', bin=True),
 
382
  alt.Tooltip('level:N', title='Level:'),
383
- alt.Tooltip('count()', title='Video count:')
384
  ],
385
  opacity=alt.condition(selection, alt.value(0.75), alt.value(0.1)),
386
  strokeWidth=alt.condition(highlight, alt.value(2), alt.value(1))
@@ -388,7 +387,7 @@ def get_sentence_length_hist(show_medians=False):
388
  width='container',
389
  height=500,
390
  title=alt.TitleParams(
391
- text='Average number of words per sentence (sentence length)',
392
  offset=20,
393
  fontSize=24,
394
  fontWeight='normal',
@@ -409,7 +408,7 @@ def get_sentence_length_hist(show_medians=False):
409
  ).encode(
410
  x='x:Q',
411
  tooltip=[
412
- alt.Tooltip('x:N', title='Median average sentence length:'),
413
  alt.Tooltip('level:N', title='Level:')
414
  ],
415
  color=alt.Color(
@@ -478,7 +477,7 @@ def get_repetition_hist(show_medians=False):
478
  alt.X(
479
  'average_rel_reps_perc:Q',
480
  bin=alt.Bin(maxbins=30),
481
- title='Average relative repetitions (%)',
482
  axis=alt.Axis(
483
  labelFontSize=14,
484
  titleFontSize=18,
@@ -520,9 +519,9 @@ def get_repetition_hist(show_medians=False):
520
  )
521
  ),
522
  tooltip=[
523
- alt.Tooltip('average_rel_reps:Q', title='Average relative repetitions:', bin=True),
 
524
  alt.Tooltip('level:N', title='Level:'),
525
- alt.Tooltip('count()', title='Video count:')
526
  ],
527
  opacity=alt.condition(selection, alt.value(0.75), alt.value(0.1)),
528
  strokeWidth=alt.condition(highlight, alt.value(2), alt.value(1))
@@ -530,7 +529,7 @@ def get_repetition_hist(show_medians=False):
530
  width='container',
531
  height=500,
532
  title=alt.TitleParams(
533
- text='Relative repetitions of words',
534
  offset=20,
535
  fontSize=24,
536
  fontWeight='normal',
@@ -553,7 +552,7 @@ def get_repetition_hist(show_medians=False):
553
  'x:Q'
554
  ),
555
  tooltip=[
556
- alt.Tooltip('x:N', title='Median average relative repetitions:'),
557
  alt.Tooltip('level:N', title='Level:')
558
  ],
559
  color=alt.Color(
@@ -664,7 +663,7 @@ def get_word_coverage_chart(zoom=False):
664
  alt.Tooltip('word:N', title='Word: '),
665
  alt.Tooltip('rank:Q', title="CIJ rank: "),
666
  alt.Tooltip('coverage_perc_str:N', title='Word coverage: '),
667
- alt.Tooltip('level:N', title='Level: ')
668
  ],
669
  opacity=alt.condition(selection, alt.value(1.0), alt.value(0.2)),
670
  strokeWidth=alt.condition(selection | highlight, alt.value(6), alt.value(2))
@@ -752,7 +751,7 @@ def get_ne_spot_hist(show_medians=False):
752
  alt.X(
753
  'ne_spot:Q',
754
  bin=alt.Bin(maxbins=30),
755
- title='Number of most common CIJ words known',
756
  axis=alt.Axis(
757
  labelFontSize=14,
758
  titleFontSize=18,
@@ -794,9 +793,9 @@ def get_ne_spot_hist(show_medians=False):
794
  )
795
  ),
796
  tooltip=[
797
- alt.Tooltip('ne_spot:Q', title='Vocab size needed for 98% cov:', bin=True),
798
- alt.Tooltip('level:N', title='Level:'),
799
- alt.Tooltip('count()', title='Video count:')
800
  ],
801
  opacity=alt.condition(selection, alt.value(0.75), alt.value(0.1)),
802
  strokeWidth=alt.condition(highlight, alt.value(2), alt.value(1))
@@ -804,7 +803,7 @@ def get_ne_spot_hist(show_medians=False):
804
  width='container',
805
  height=500,
806
  title=alt.TitleParams(
807
- text='Vocab size needed for 98% coverage',
808
  offset=20,
809
  fontSize=24,
810
  fontWeight='normal',
@@ -930,9 +929,9 @@ def get_tfplr_hist(show_medians=False):
930
  )
931
  ),
932
  tooltip=[
933
- alt.Tooltip('tfp_log_ranks_unique:Q', title='25th percentile word-frequency log rank:', bin=True), # Properly indicate that `wpm` is binned
 
934
  alt.Tooltip('level:N', title='Level:'),
935
- alt.Tooltip('count()', title='Video count:')
936
  ],
937
  opacity=alt.condition(selection, alt.value(0.75), alt.value(0.1)),
938
  strokeWidth=alt.condition(highlight, alt.value(2), alt.value(1))
@@ -961,7 +960,7 @@ def get_tfplr_hist(show_medians=False):
961
  ).encode(
962
  x='x:Q',
963
  tooltip=[
964
- alt.Tooltip('x:N', title='Median 25th percentile word-frequency log rank:'),
965
  alt.Tooltip('level:N', title='Level:')
966
  ],
967
  color=alt.Color(
@@ -1025,7 +1024,7 @@ def get_sconj_hist(show_medians=False):
1025
  alt.X(
1026
  'sconj_props_perc:Q',
1027
  bin=alt.Bin(maxbins=30),
1028
- title='Percentage of words',
1029
  axis=alt.Axis(
1030
  labelFontSize=14,
1031
  titleFontSize=18,
@@ -1067,9 +1066,9 @@ def get_sconj_hist(show_medians=False):
1067
  )
1068
  ),
1069
  tooltip=[
1070
- alt.Tooltip('sconj_props_perc:Q', title='Percentage of subordinating conjunctions:', bin=True),
 
1071
  alt.Tooltip('level:N', title='Level:'),
1072
- alt.Tooltip('count()', title='Video count:')
1073
  ],
1074
  opacity=alt.condition(selection, alt.value(0.75), alt.value(0.1)),
1075
  strokeWidth=alt.condition(highlight, alt.value(2), alt.value(1))
@@ -1077,7 +1076,7 @@ def get_sconj_hist(show_medians=False):
1077
  width='container',
1078
  height=500,
1079
  title=alt.TitleParams(
1080
- text='Percentages of subordinating conjunctions',
1081
  offset=20,
1082
  fontSize=24,
1083
  fontWeight='normal',
@@ -1098,7 +1097,7 @@ def get_sconj_hist(show_medians=False):
1098
  ).encode(
1099
  x='x:Q',
1100
  tooltip=[
1101
- alt.Tooltip('x:N', title='Median percentage of subordinating conjunctions:'),
1102
  alt.Tooltip('level:N', title='Level:')
1103
  ],
1104
  color=alt.Color(
@@ -1163,7 +1162,7 @@ def get_kango_hist(show_medians=False):
1163
  alt.X(
1164
  'kan_props_perc:Q',
1165
  bin=alt.Bin(maxbins=30),
1166
- title='Percentage of words',
1167
  axis=alt.Axis(
1168
  labelFontSize=14,
1169
  titleFontSize=18,
@@ -1206,8 +1205,8 @@ def get_kango_hist(show_medians=False):
1206
  ),
1207
  tooltip=[
1208
  alt.Tooltip('kan_props_perc:Q', title='Percentage of kango:', bin=True),
 
1209
  alt.Tooltip('level:N', title='Level:'),
1210
- alt.Tooltip('count()', title='Video count:')
1211
  ],
1212
  opacity=alt.condition(selection, alt.value(0.75), alt.value(0.1)),
1213
  strokeWidth=alt.condition(highlight, alt.value(2), alt.value(1))
@@ -1215,7 +1214,7 @@ def get_kango_hist(show_medians=False):
1215
  width='container',
1216
  height=500,
1217
  title=alt.TitleParams(
1218
- text='Percentages of kango (漢語)',
1219
  offset=20,
1220
  fontSize=24,
1221
  fontWeight='normal',
@@ -1236,7 +1235,7 @@ def get_kango_hist(show_medians=False):
1236
  ).encode(
1237
  x='x:Q',
1238
  tooltip=[
1239
- alt.Tooltip('x:N', title='Median percentage of kango:'),
1240
  alt.Tooltip('level:N', title='Level:')
1241
  ],
1242
  color=alt.Color(
@@ -1278,7 +1277,7 @@ def get_kango_hist(show_medians=False):
1278
 
1279
  return layered_chart
1280
 
1281
- #@st.cache_data
1282
  def render_vanilla_heatmap():
1283
 
1284
  corr_matrix = num_video_df.corr()
@@ -1290,14 +1289,14 @@ def render_vanilla_heatmap():
1290
  sorted_corr_matrix = corr_matrix.loc[sorted_vars, sorted_vars]
1291
 
1292
  plt.figure(figsize=(10, 8))
1293
- sns.heatmap(sorted_corr_matrix, annot=True, cmap='coolwarm', fmt=".3f")
1294
 
1295
  st.pyplot(plt.gcf())
1296
 
1297
- #@st.cache_data
1298
  def render_level_row_unordered():
1299
 
1300
- corr_matrix = num_video_df.drop(['Proportion of determiners', 'Proportion of nouns', 'Proportion of wago', 'Proportion of gairaigo'], axis=1).corr()
1301
 
1302
  variable_of_interest = 'Level'
1303
 
@@ -1312,10 +1311,10 @@ def render_level_row_unordered():
1312
 
1313
  st.pyplot(plt.gcf())
1314
 
1315
- #@st.cache_data
1316
  def render_level_col_ordered():
1317
 
1318
- corr_matrix = num_video_df.drop(['Proportion of determiners', 'Proportion of nouns', 'Proportion of wago', 'Proportion of gairaigo'], axis=1).corr()
1319
 
1320
  variable_of_interest = 'Level'
1321
 
@@ -1348,7 +1347,7 @@ highlight = alt.selection_point(name="highlight", fields=['level'], on='mouseove
1348
  ###
1349
  st.markdown("Note: this analysis is meant to viewed on a computer and not a phone (sorry!)")
1350
 
1351
- st.markdown("[Code can be found [here](https://github.com/joshdavham/cij-analysis)]")
1352
 
1353
  st.markdown("# What makes comprehensible input *comprehensible*?")
1354
 
@@ -1371,7 +1370,9 @@ st.markdown("If we measure how fast the teachers speak on CIJ, we find that \
1371
  they speak more slowly in videos meant for beginners and more quickly \
1372
  for advanced learners.")
1373
 
1374
- if st.checkbox('Show medians'):
 
 
1375
  layered_chart = get_wpm_chart(show_medians=True)
1376
  else:
1377
  layered_chart = get_wpm_chart(show_medians=False)
@@ -1379,7 +1380,7 @@ else:
1379
  st.altair_chart(layered_chart, use_container_width=True)
1380
 
1381
  st.markdown("To put this data into perspective, native Japanese speakers \
1382
- tend to speak at rates of over 200 wpm, meaning that most of the videos \
1383
  on CIJ have been adapted to be a lot slower than that!")
1384
 
1385
  if st.checkbox('Enable zooming and panning ( ↕ / ↔️ )'):
@@ -1392,9 +1393,6 @@ st.altair_chart(wpm_vs_sps_chart, use_container_width=True)
1392
  st.markdown("We can also measure the rate of speech in syllables per second (SPS) \
1393
  and compare it to words per minute.")
1394
 
1395
- st.markdown("(Also, FYI, most of these **graphs are \
1396
- interactive** so please click around.)")
1397
-
1398
  ###
1399
  # STATISTICS LESSON
1400
  ###
@@ -1436,7 +1434,7 @@ st.markdown("## Sentence length")
1436
 
1437
  st.markdown("Videos meant for beginners tend to have shorter sentences on average.")
1438
 
1439
- if st.checkbox('Show medians', key='sentence_length'):
1440
  sentence_length_hist = get_sentence_length_hist(show_medians=True)
1441
  else:
1442
  sentence_length_hist = get_sentence_length_hist(show_medians=False)
@@ -1453,7 +1451,7 @@ st.markdown("## Amount of repetition")
1453
 
1454
  st.markdown("Words are repeated more often in easier videos.")
1455
 
1456
- if st.checkbox('Show medians', key='repetition'):
1457
  repetition_hist = get_repetition_hist(show_medians=True)
1458
  else:
1459
  repetition_hist = get_repetition_hist(show_medians=False)
@@ -1490,7 +1488,7 @@ st.markdown("Using the same method of calculating word coverage as before, \
1490
  we can also calculate how many of the top words you need to know \
1491
  to achieve 98% word coverage in each video.")
1492
 
1493
- if st.checkbox('Show medians', key='ne_spot'):
1494
  ne_spot_hist = get_ne_spot_hist(show_medians=True)
1495
  else:
1496
 
@@ -1507,7 +1505,8 @@ st.markdown("## Word rareness")
1507
 
1508
  st.markdown("More advanced videos tend to use rare/uncommon words more often than easier videos.")
1509
 
1510
- if st.checkbox('Show medians', key='tfplr'):
 
1511
  tfplr_hist = get_tfplr_hist(show_medians=True)
1512
  else:
1513
  tfplr_hist = get_tfplr_hist(show_medians=False)
@@ -1533,9 +1532,9 @@ st.markdown("(It's okay ff the above didn't quite make sense to you - just know
1533
  ###
1534
  st.markdown("## Grammar")
1535
 
1536
- st.markdown("Easier videos tend to use less [subordinating conjunctions](https://universaldependencies.org/u/pos/SCONJ.html) than harder videos.")
1537
 
1538
- if st.checkbox('Show medians', key='sconj'):
1539
  sconj_hist = get_sconj_hist(show_medians=True)
1540
  else:
1541
  sconj_hist = get_sconj_hist(show_medians=False)
@@ -1559,7 +1558,7 @@ st.markdown("Wago are native Japanese words, Kango are Chinese words and Gairaig
1559
 
1560
  st.markdown("Harder videos tend to use more Kango than easier videos")
1561
 
1562
- if st.checkbox('Show medians', key='kango'):
1563
  kango_hist = get_kango_hist(show_medians=True)
1564
  else:
1565
  kango_hist = get_kango_hist(show_medians=False)
@@ -1596,7 +1595,7 @@ st.markdown("In case you're not familiar with stuff like this, numbers close to
1596
  st.markdown("Using a statistics rule of thumb and removing all variables that have correlations \
1597
  weaker than 0.3 (and more than -0.3), we can identify the variables with the strongest correlations.")
1598
 
1599
- if st.checkbox('Flip and sort'):
1600
  render_level_col_ordered()
1601
  else:
1602
  render_level_row_unordered()
@@ -1610,9 +1609,58 @@ st.markdown("3. Amount of repetition of words")
1610
  st.markdown("4. How common/rare the words are")
1611
  st.markdown("5. Amount of subordinating conjunctions")
1612
  st.markdown("6. Vocabulary size")
1613
- st.markdown("7. Amount of adverbs")
1614
- st.markdown("8. Amount of Chinese words")
 
 
 
 
 
 
1615
 
1616
  st.markdown("### Thanks for reading ✌️")
1617
 
1618
- st.markdown("---")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  def get_grammar_table():
34
 
35
  data = {
36
+ 'Complete Beginner': [0.02638719922016275 ,0.0192492959834, 0.00476028625918155, 0.2503071253071253, 0.18554386037363785, 0.01622086690206438, 0.04537920642893019, 0.1203097143691203],
37
+ 'Beginner': [0.0473047304730473, 0.0266429840142095, 0.005813953488372, 0.2454068241469816, 0.1773049645390071, 0.01384083044982699, 0.02676864244741874, 0.13333333333333333],
38
+ 'Intermediate': [0.06625719079578135, 0.03514773095199635, 0.0087719298245614, 0.23239271705403663, 0.1587691162151326, 0.010784997932175352, 0.022392603507910194, 0.13379268084136123],
39
+ 'Advanced': [0.0766787658802177, 0.0373056994818652, 0.0108588351431391, 0.2237101220953131, 0.14922184925236498, 0.009050978304272594, 0.020185708518368994, 0.1364369670430975]
40
  }
41
  df = pd.DataFrame(data)
42
 
43
+ row_labels = ['Median Perc. Subordinating Conjunctions', 'Median Perc. Adverbs', 'Median Perc. Determiners', 'Median Perc. Nouns', 'Median Perc. Auxiliaries', 'Median Perc. Numerals', 'Median Perc. Pronouns', 'Median Perc. Verbs']
44
  df.index = row_labels
45
 
46
  styled_df = df.style.set_table_styles(
 
164
  ),
165
  tooltip=[
166
  alt.Tooltip('wpm:Q', title='Words per minute:', bin=True),
167
+ alt.Tooltip('count()', title='Video count:'),
168
  alt.Tooltip('level:N', title='Level:'),
 
169
  ],
170
  opacity=alt.condition(selection, alt.value(0.75), alt.value(0.1)),
171
  strokeWidth=alt.condition(highlight, alt.value(2), alt.value(1))
 
285
  ),
286
  tooltip=[
287
  alt.Tooltip('video:N', title='Video number:'),
 
288
  alt.Tooltip('wpm:Q', title='WPM:'),
289
  alt.Tooltip('sps:Q', title='SPS:'),
290
+ alt.Tooltip('level:N', title='Level:'),
291
  ],
292
  opacity=alt.condition(selection, alt.value(1.0), alt.value(0.2)),
293
  ).properties(
 
335
  alt.X(
336
  'mean_sentence_length:Q',
337
  bin=alt.Bin(maxbins=30),
338
+ title='Words per sentence',
339
  axis=alt.Axis(
340
  labelFontSize=14,
341
  titleFontSize=18,
 
378
  ),
379
  tooltip=[
380
  alt.Tooltip('mean_sentence_length:Q', title='Average sentence length:', bin=True),
381
+ alt.Tooltip('count()', title='Video count:'),
382
  alt.Tooltip('level:N', title='Level:'),
 
383
  ],
384
  opacity=alt.condition(selection, alt.value(0.75), alt.value(0.1)),
385
  strokeWidth=alt.condition(highlight, alt.value(2), alt.value(1))
 
387
  width='container',
388
  height=500,
389
  title=alt.TitleParams(
390
+ text='Average sentence length (words per sentence)',
391
  offset=20,
392
  fontSize=24,
393
  fontWeight='normal',
 
408
  ).encode(
409
  x='x:Q',
410
  tooltip=[
411
+ alt.Tooltip('x:N', title='Median avg. sentence length:'),
412
  alt.Tooltip('level:N', title='Level:')
413
  ],
414
  color=alt.Color(
 
477
  alt.X(
478
  'average_rel_reps_perc:Q',
479
  bin=alt.Bin(maxbins=30),
480
+ title='Word repetitions (%)',
481
  axis=alt.Axis(
482
  labelFontSize=14,
483
  titleFontSize=18,
 
519
  )
520
  ),
521
  tooltip=[
522
+ alt.Tooltip('average_rel_reps:Q', title='Average repetitions (%):', bin=True),
523
+ alt.Tooltip('count()', title='Video count:'),
524
  alt.Tooltip('level:N', title='Level:'),
 
525
  ],
526
  opacity=alt.condition(selection, alt.value(0.75), alt.value(0.1)),
527
  strokeWidth=alt.condition(highlight, alt.value(2), alt.value(1))
 
529
  width='container',
530
  height=500,
531
  title=alt.TitleParams(
532
+ text='Average amount of repetition per word',
533
  offset=20,
534
  fontSize=24,
535
  fontWeight='normal',
 
552
  'x:Q'
553
  ),
554
  tooltip=[
555
+ alt.Tooltip('x:N', title='Median avg. repetitions (%):'),
556
  alt.Tooltip('level:N', title='Level:')
557
  ],
558
  color=alt.Color(
 
663
  alt.Tooltip('word:N', title='Word: '),
664
  alt.Tooltip('rank:Q', title="CIJ rank: "),
665
  alt.Tooltip('coverage_perc_str:N', title='Word coverage: '),
666
+ alt.Tooltip('level:N', title='Curve: ')
667
  ],
668
  opacity=alt.condition(selection, alt.value(1.0), alt.value(0.2)),
669
  strokeWidth=alt.condition(selection | highlight, alt.value(6), alt.value(2))
 
751
  alt.X(
752
  'ne_spot:Q',
753
  bin=alt.Bin(maxbins=30),
754
+ title='Number of words known',
755
  axis=alt.Axis(
756
  labelFontSize=14,
757
  titleFontSize=18,
 
793
  )
794
  ),
795
  tooltip=[
796
+ alt.Tooltip('ne_spot:Q', title='Vocab size for 98%.:', bin=True),
797
+ alt.Tooltip('count()', title='Video count:'),
798
+ alt.Tooltip('level:N', title='Level:')
799
  ],
800
  opacity=alt.condition(selection, alt.value(0.75), alt.value(0.1)),
801
  strokeWidth=alt.condition(highlight, alt.value(2), alt.value(1))
 
803
  width='container',
804
  height=500,
805
  title=alt.TitleParams(
806
+ text='Vocab size needed for 98% coverage (videos)',
807
  offset=20,
808
  fontSize=24,
809
  fontWeight='normal',
 
929
  )
930
  ),
931
  tooltip=[
932
+ alt.Tooltip('tfp_log_ranks_unique:Q', title='25th perc. log rank:', bin=True), # Properly indicate that `wpm` is binned
933
+ alt.Tooltip('count()', title='Video count:'),
934
  alt.Tooltip('level:N', title='Level:'),
 
935
  ],
936
  opacity=alt.condition(selection, alt.value(0.75), alt.value(0.1)),
937
  strokeWidth=alt.condition(highlight, alt.value(2), alt.value(1))
 
960
  ).encode(
961
  x='x:Q',
962
  tooltip=[
963
+ alt.Tooltip('x:N', title='Median 25th perc. log rank:'),
964
  alt.Tooltip('level:N', title='Level:')
965
  ],
966
  color=alt.Color(
 
1024
  alt.X(
1025
  'sconj_props_perc:Q',
1026
  bin=alt.Bin(maxbins=30),
1027
+ title='Percentage of sub. conj.',
1028
  axis=alt.Axis(
1029
  labelFontSize=14,
1030
  titleFontSize=18,
 
1066
  )
1067
  ),
1068
  tooltip=[
1069
+ alt.Tooltip('sconj_props_perc:Q', title='Perc. sub. conj:', bin=True),
1070
+ alt.Tooltip('count()', title='Video count:'),
1071
  alt.Tooltip('level:N', title='Level:'),
 
1072
  ],
1073
  opacity=alt.condition(selection, alt.value(0.75), alt.value(0.1)),
1074
  strokeWidth=alt.condition(highlight, alt.value(2), alt.value(1))
 
1076
  width='container',
1077
  height=500,
1078
  title=alt.TitleParams(
1079
+ text='Frequency of subordinating conjunctions',
1080
  offset=20,
1081
  fontSize=24,
1082
  fontWeight='normal',
 
1097
  ).encode(
1098
  x='x:Q',
1099
  tooltip=[
1100
+ alt.Tooltip('x:N', title='Median perc. of sub. conj:'),
1101
  alt.Tooltip('level:N', title='Level:')
1102
  ],
1103
  color=alt.Color(
 
1162
  alt.X(
1163
  'kan_props_perc:Q',
1164
  bin=alt.Bin(maxbins=30),
1165
+ title='Percentage of kango',
1166
  axis=alt.Axis(
1167
  labelFontSize=14,
1168
  titleFontSize=18,
 
1205
  ),
1206
  tooltip=[
1207
  alt.Tooltip('kan_props_perc:Q', title='Percentage of kango:', bin=True),
1208
+ alt.Tooltip('count()', title='Video count:'),
1209
  alt.Tooltip('level:N', title='Level:'),
 
1210
  ],
1211
  opacity=alt.condition(selection, alt.value(0.75), alt.value(0.1)),
1212
  strokeWidth=alt.condition(highlight, alt.value(2), alt.value(1))
 
1214
  width='container',
1215
  height=500,
1216
  title=alt.TitleParams(
1217
+ text='Frequency of kango',
1218
  offset=20,
1219
  fontSize=24,
1220
  fontWeight='normal',
 
1235
  ).encode(
1236
  x='x:Q',
1237
  tooltip=[
1238
+ alt.Tooltip('x:N', title='Median perc. kango:'),
1239
  alt.Tooltip('level:N', title='Level:')
1240
  ],
1241
  color=alt.Color(
 
1277
 
1278
  return layered_chart
1279
 
1280
+ @st.cache_data
1281
  def render_vanilla_heatmap():
1282
 
1283
  corr_matrix = num_video_df.corr()
 
1289
  sorted_corr_matrix = corr_matrix.loc[sorted_vars, sorted_vars]
1290
 
1291
  plt.figure(figsize=(10, 8))
1292
+ sns.heatmap(sorted_corr_matrix, annot=True, cmap='coolwarm', fmt=".2f")
1293
 
1294
  st.pyplot(plt.gcf())
1295
 
1296
+ @st.cache_data
1297
  def render_level_row_unordered():
1298
 
1299
+ corr_matrix = num_video_df.drop(['Proportion of determiners', 'Proportion of nouns', 'Proportion of wago', 'Proportion of gairaigo', 'Proportion of verbs', 'Proportion of numerals'], axis=1).corr()
1300
 
1301
  variable_of_interest = 'Level'
1302
 
 
1311
 
1312
  st.pyplot(plt.gcf())
1313
 
1314
+ @st.cache_data
1315
  def render_level_col_ordered():
1316
 
1317
+ corr_matrix = num_video_df.drop(['Proportion of determiners', 'Proportion of nouns', 'Proportion of wago', 'Proportion of gairaigo', 'Proportion of verbs', 'Proportion of numerals'], axis=1).corr()
1318
 
1319
  variable_of_interest = 'Level'
1320
 
 
1347
  ###
1348
  st.markdown("Note: this analysis is meant to viewed on a computer and not a phone (sorry!)")
1349
 
1350
+ st.markdown("[Code and data can be found [here](https://github.com/joshdavham/cij-analysis)]")
1351
 
1352
  st.markdown("# What makes comprehensible input *comprehensible*?")
1353
 
 
1370
  they speak more slowly in videos meant for beginners and more quickly \
1371
  for advanced learners.")
1372
 
1373
+ st.markdown("**(THESE GRAPHS ARE CLICKABLE)**")
1374
+
1375
+ if st.checkbox('Show medians', value=True, key='wpm'):
1376
  layered_chart = get_wpm_chart(show_medians=True)
1377
  else:
1378
  layered_chart = get_wpm_chart(show_medians=False)
 
1380
  st.altair_chart(layered_chart, use_container_width=True)
1381
 
1382
  st.markdown("To put this data into perspective, native Japanese speakers \
1383
+ can speak at rates of over 200 wpm, meaning that most of the videos \
1384
  on CIJ have been adapted to be a lot slower than that!")
1385
 
1386
  if st.checkbox('Enable zooming and panning ( ↕ / ↔️ )'):
 
1393
  st.markdown("We can also measure the rate of speech in syllables per second (SPS) \
1394
  and compare it to words per minute.")
1395
 
 
 
 
1396
  ###
1397
  # STATISTICS LESSON
1398
  ###
 
1434
 
1435
  st.markdown("Videos meant for beginners tend to have shorter sentences on average.")
1436
 
1437
+ if st.checkbox('Show medians', value=True, key='sentence_length'):
1438
  sentence_length_hist = get_sentence_length_hist(show_medians=True)
1439
  else:
1440
  sentence_length_hist = get_sentence_length_hist(show_medians=False)
 
1451
 
1452
  st.markdown("Words are repeated more often in easier videos.")
1453
 
1454
+ if st.checkbox('Show medians', value=True, key='repetition'):
1455
  repetition_hist = get_repetition_hist(show_medians=True)
1456
  else:
1457
  repetition_hist = get_repetition_hist(show_medians=False)
 
1488
  we can also calculate how many of the top words you need to know \
1489
  to achieve 98% word coverage in each video.")
1490
 
1491
+ if st.checkbox('Show medians', value=True, key='ne_spot'):
1492
  ne_spot_hist = get_ne_spot_hist(show_medians=True)
1493
  else:
1494
 
 
1505
 
1506
  st.markdown("More advanced videos tend to use rare/uncommon words more often than easier videos.")
1507
 
1508
+ if st.checkbox('Show medians', value=True, key='tfplr'):
1509
+ # tfplr stands for "twenty fifth percentile log rank"
1510
  tfplr_hist = get_tfplr_hist(show_medians=True)
1511
  else:
1512
  tfplr_hist = get_tfplr_hist(show_medians=False)
 
1532
  ###
1533
  st.markdown("## Grammar")
1534
 
1535
+ st.markdown("Easier videos tend to use less [subordinating conjunctions](https://universaldependencies.org/ja/pos/SCONJ.html) than harder videos.")
1536
 
1537
+ if st.checkbox('Show medians', value=True, key='sconj'):
1538
  sconj_hist = get_sconj_hist(show_medians=True)
1539
  else:
1540
  sconj_hist = get_sconj_hist(show_medians=False)
 
1558
 
1559
  st.markdown("Harder videos tend to use more Kango than easier videos")
1560
 
1561
+ if st.checkbox('Show medians', value=True, key='kango'):
1562
  kango_hist = get_kango_hist(show_medians=True)
1563
  else:
1564
  kango_hist = get_kango_hist(show_medians=False)
 
1595
  st.markdown("Using a statistics rule of thumb and removing all variables that have correlations \
1596
  weaker than 0.3 (and more than -0.3), we can identify the variables with the strongest correlations.")
1597
 
1598
+ if st.checkbox('Flip and sort by correlation strength'):
1599
  render_level_col_ordered()
1600
  else:
1601
  render_level_row_unordered()
 
1609
  st.markdown("4. How common/rare the words are")
1610
  st.markdown("5. Amount of subordinating conjunctions")
1611
  st.markdown("6. Vocabulary size")
1612
+ st.markdown("7. Amount of pronouns")
1613
+ st.markdown("8. Amount of adverbs")
1614
+ st.markdown("9. Amount of auxiliaries")
1615
+ st.markdown("10. Amount of Chinese words")
1616
+
1617
+ st.markdown("## Dicussion")
1618
+
1619
+ #st.markdown('')
1620
 
1621
  st.markdown("### Thanks for reading ✌️")
1622
 
1623
+ st.markdown("---")
1624
+
1625
+ st.markdown("#### Futher discussion for hardcore nerds")
1626
+
1627
+ st.markdown("- No tests of statistical significance were conducted. This was purely meant as an EDA. \
1628
+ However, you can get the data from the repo linked at the top and conduct them yourself if you'd like. \
1629
+ I'd recommend starting with non-parametric tests like Kruskal-Wallis and moving on to pairwise tests \
1630
+ with a bonferonni correction if it's significant. Parametric tests may also be interesting.")
1631
+
1632
+ st.markdown("- Technically, I computed 'moras per second' - not syllables per second. I'm aware that this \
1633
+ is technically linguistically incorrect, but it still serves as close approximation and is easier \
1634
+ to understand for readers unfamiliar with Japanese linguistics.")
1635
+
1636
+ st.markdown("- The Mecab and Sudachi parsers (through Fugashi and Spacy) were used to analyze the transcripts. These parsers are not always 100% accurate.")
1637
+
1638
+ st.markdown("- When computing the statistics for repetition, word coverage and word frequency, lemmas were used rather than tokens.")
1639
+
1640
+ st.markdown("- Of the parsed words, while I did remove punctuation, I didn't otherwise verify that each token was an actual word. \
1641
+ There is likely some amount of noise in the data such as mis-parses, etc.")
1642
+
1643
+ st.markdown("- If you're like me, the word coverage plots also probably evoked a resemblance to Heap's Law. \
1644
+ More research would need to be done, but I suspect one may be able to find a link between word coverage and Heap's Law.")
1645
+
1646
+ st.markdown("- One should bare in mind that the learner levels were labelled by a small group of experts and not a large number of learners. \
1647
+ In other words, the difficulty levels are not objective, but rather an approximation of difficulty / natural acquistion order.")
1648
+
1649
+ st.markdown("- There were a number of statistics I also tried but didn't get orderings from:")
1650
+
1651
+ st.markdown("1. **Audibility** - My hypothesis was that the teachers would speak more clearly in easy videos and less clearly in harder videos. \
1652
+ To test this, I generated whisper transcripts for each video's audio file, converted both the whisper transcript \
1653
+ and the original transcript to katakana and compared the character error rate. I found no differences in the levels. \
1654
+ Furthermore I can't tell if this moreso invalidates my original hypothesis or if whisper is just that good.")
1655
+
1656
+ st.markdown("2. **Word length** - At least in English and French (the languages I know the best), longer words are generally considered harder. \
1657
+ My hypothesis was that the easier videos would use shorter words while the harder videos would use bigger words. \
1658
+ To test this, I parsed the transcripts and converted all words to katakana \
1659
+ to get a measure of how long the words were orally. I found no differences between the levels.")
1660
+
1661
+ st.markdown("3. **Range of vocabulary** - I suspected that easier videos may limit themselves to a smaller range of vocabulary than harder videos. \
1662
+ To measure this, I calculated unique word occurences / total word occurences but I found no ordering in the levels.")
1663
+
1664
+ st.markdown("4. **Other parts of speech** - I did test for orderings between the levels for other parts of speech such as: \
1665
+ proportion of adjectives, adpositions, coordinating conjunctions, interjections, particles and proper nouns \
1666
+ but ultimately didn't find any obvious orderings.")