Spaces:
Runtime error
Runtime error
Commit ·
34cc53e
1
Parent(s): 38a1839
more modifications to source
Browse files
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='
|
| 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
|
| 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
|
| 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='
|
| 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
|
|
|
|
| 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='
|
| 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
|
| 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='
|
| 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
|
| 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
|
| 798 |
-
alt.Tooltip('
|
| 799 |
-
alt.Tooltip('
|
| 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
|
|
|
|
| 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
|
| 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
|
| 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='
|
|
|
|
| 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='
|
| 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
|
| 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
|
| 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='
|
| 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
|
| 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 |
-
|
| 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=".
|
| 1294 |
|
| 1295 |
st.pyplot(plt.gcf())
|
| 1296 |
|
| 1297 |
-
|
| 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 |
-
|
| 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 |
-
|
|
|
|
|
|
|
| 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 |
-
|
| 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/
|
| 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
|
| 1614 |
-
st.markdown("8. Amount of
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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.")
|