Introduction

This document is part of a series dedicated to a corpus-based analysis of articles on Japan- and U.S.-returned students in Dongfang zazhi 東方雜誌 (The Eastern Miscellany). Building on a previous script aimed at constructing and exploring a corpus focused on Japan-returned students, this document provides code for extracting and analyzing biographical information about the authors of these articles. # Authorship Information

Extraction/Curation

# clean authors' names

library(dplyr)
library(tidyr)

liuri_authors <- liuri_clean %>% select(DocId, authors) %>%
  mutate(Author = str_replace_all(authors, "\\[", "")) %>%
  mutate(Author = str_replace_all(Author, "\\]", ""))%>%
  mutate(Author = str_replace_all(Author, "\\'", "")) %>%
  separate_rows(Author, sep = ",\\s*")
liuri_authors

Basic statistics

liuri_authors %>% group_by(Author) %>% count(sort = TRUE) # number of articles by author
liuri_authors %>% group_by(DocId) %>% count(sort = TRUE) # co-authored articles

Biographical Information

We searched for biographical information on the authors in Chinese Wikipedia and the Who’s Who publications provided by the Institute of Modern History (IMH), Academia Sinica, Taipei.

# Create a function for multiple queries 

multiple_search <- function(queries, corpus) {
  results <- histtext::search_documents_ex(queries[1], corpus) %>%
    mutate(Q=queries[1])
  for(q in queries){
    new_result <- histtext::search_documents_ex(q, corpus) %>%
      mutate(Q=q)
    results <- dplyr::bind_rows(results, new_result)
  }
  distinct(results)
}

# Create the list of names to query 

liuri_authors_list <- liuri_authors %>% drop_na(Author) %>% filter(!Author == "留日學生") %>% mutate(Queries=str_glue('"{Author}"')) 

Wikipedia

library(histtext)

liuri_authors_wiki <- multiple_search(liuri_authors_list$Queries, "wikibio-zh") # 338 results
liuri_authors_wiki <- liuri_authors_wiki %>% group_by(Q) %>% add_tally()

# Eliminate irrelevant results 

liuri_list_names <- liuri_authors_list$Author
liuri_list_names <-  paste(liuri_list_names, sep = "", collapse = "|")
liuri_authors_wiki <- liuri_authors_wiki %>% mutate(title_match = str_extract(Title, liuri_list_names))
liuri_authors_wiki <- liuri_authors_wiki %>% group_by(title_match) %>% add_tally()

liuri_authors_wiki_match <- liuri_authors_wiki %>% filter(!is.na(title_match)) # 14 matches

# 14 bios remain
liuri_authors_wiki_match
# Extract the full text of biographies

liuri_authors_wiki_ft <- histtext::get_documents(liuri_authors_wiki_match, "wikibio-zh")
liuri_authors_wiki_ft

Who’s Who (IMH collection)

library(histtext)

liuri_authors_imh <- multiple_search(liuri_authors_list$Queries, "imh-zh") # 117 results

liuri_authors_imh <- liuri_authors_imh %>% mutate(title_match = str_extract(Title, liuri_list_names))
liuri_authors_imh <- liuri_authors_imh %>% group_by(title_match) %>% add_tally()

# Eliminate irrelevant results 

liuri_authors_imh_match <- liuri_authors_imh %>% filter(!is.na(title_match)) #  69 results remain

liuri_authors_imh_match <- liuri_authors_imh_match %>% distinct(DocId, Title) %>% 
  mutate(Title_clean = str_replace(Title, "【", ""))  %>% 
  mutate(Title_clean = str_replace(Title_clean, "】", "")) %>% 
  mutate(Title_clean = str_extract(Title_clean, "^.{3}")) %>% relocate(title_match, .after = Title_clean)

liuri_authors_imh_match <- liuri_authors_imh_match %>% mutate(title_length = nchar(Title)) %>% mutate(title_length2 = nchar(Title_clean)) %>%
  mutate(query_length = nchar(title_match)) %>% mutate(dif = (query_length-title_length))  %>% mutate(dif2 = (query_length-title_length2))

liuri_authors_imh_filtered <- liuri_authors_imh_match %>% filter(!dif2 == "-1")

liuri_authors_imh_unique <- liuri_authors_imh_filtered %>% 
  select(DocId, title_match) %>% rename(Name = title_match) %>% 
  group_by(Name) %>% count() 

liuri_authors_imh_filtered <- liuri_authors_imh_filtered %>% select(DocId, title_match) %>% rename(Name = title_match)

# 49 biographies remain, referring to 13 unique names (from 1 to 6 biographies per author)
liuri_authors_imh_filtered
# Retrieve full text 

liuri_authors_imh_ft <- histtext::get_documents(liuri_authors_imh_filtered, "imh-zh")
liuri_authors_imh_ft

Biographical Attributes

## Bind the two datasets 

liuri_authors_bio <- bind_rows(liuri_authors_imh_ft, liuri_authors_wiki_ft)

Year of Birth

# Retrieve year of birth 

liuri_authors_bio$year <- regmatches(liuri_authors_bio$Text, gregexpr("\\d{4}", liuri_authors_bio$Text))
liuri_authors_bio$birth <- regmatches(liuri_authors_bio$year, regexpr("[[:digit:]]+", liuri_authors_bio$year))
liuri_authors_bio$year <- NULL
liuri_authors_bio_filtered <- liuri_authors_bio %>% filter(birth < 1948) %>% filter(birth > 1800) # 20 names remain
liuri_authors_bio_filtered

Native Place

# Retrieve native provinces based on list 

library(readr)
provinces <- read_delim("~/indexes/provinces.csv",
                       delim = ";", escape_double = FALSE, trim_ws = TRUE)

provinces <- provinces %>% na.omit()

# create vector 

prov_list <- provinces$Province
prov_list <-  paste(prov_list, sep = "", collapse = "|")
liuri_authors_bio_filtered <- liuri_authors_bio_filtered %>% mutate(birthplace = str_extract(Text, prov_list))

Education

# Retrieve academic disciplines based on typology

# Load typology 

library(readr)
disciplines <- read_delim("~/indexes/disciplines.csv", 
                                    delim = ";", escape_double = FALSE, trim_ws = TRUE)

# create vector

disc_list <- disciplines$Level2__ZhT_MCBD
disc_vec <-  paste(disc_list, sep = "", collapse = "|")

liuri_authors_bio_filtered <- liuri_authors_bio_filtered %>% 
  mutate(discipline = str_extract_all(Text, disc_vec)) %>% 
  mutate(discipline = as.character(discipline))
# identify those who studied or traveled to foreign countries 

liuri_authors_bio_filtered <- liuri_authors_bio_filtered %>% 
  mutate(edu_country = str_extract_all(Text, "留美|留日|留法|留德|留英")) %>% 
  mutate(edu_country = as.character(edu_country)) %>% 
  mutate(country = str_extract_all(Text, "美國|日本|法國|德國|英國")) %>% 
  mutate(country = as.character(country))
liuri_authors_bio_filtered

Named Entity Recognition (NER)

In the following section, we extract named entities from biographies using models specifically developed by the ENP-China team for modern Chinese historical texts, integrated into the HistText package.

Extraction

liuri_authors_imh_ner <- ner_on_corpus(liuri_authors_imh_ft, corpus = "imh-zh") 
liuri_authors_wiki_ner <- ner_on_corpus(liuri_authors_wiki_ft, corpus = "wikibio-zh")
liuri_authors_ner <- bind_rows(liuri_authors_imh_ner, liuri_authors_wiki_ner) # bind the two lists
liuri_authors_ner


In the following section, we focus on organizations to define occupational profiles, but we could also examine other types of entities, such as events in which they were involved or creative works they produced during their careers.

Curation

# Filter organizations

liuri_authors_org <- liuri_authors_ner %>% filter(Type == "ORG") 

# Preliminary cleaning 

liuri_authors_org <- liuri_authors_org %>% 
  mutate(text_clean = str_replace(Text, "《", "")) %>% 
  mutate(text_clean = str_replace(text_clean, ">", "")) %>% 
  relocate(text_clean, .after = Text) %>% 
  mutate(text_clean, text_clean=str_replace(text_clean,"(.*","")) %>% 
  mutate(text_clean, text_clean=str_replace(text_clean,"\\(.*","")) %>% 
  mutate(text_clean, text_clean=str_replace(text_clean,"\\(.*",""))%>% 
  mutate(text_clean = str_replace(text_clean, " ", "")) %>% 
  mutate(text_clean = str_replace(text_clean, " ", ""))%>% 
  mutate(length = nchar(text_clean)) %>% 
  relocate(length, .after = text_clean) 

liuri_authors_org <- liuri_authors_org %>% filter(length > 1) # 463

# Extract suffixes and prefixes to help classify and locate institutions 

liuri_authors_org <- liuri_authors_org %>% 
  mutate(class = str_sub(text_clean,-2,-1)) %>% 
  relocate(class, .after = text_clean) 

liuri_authors_org <- liuri_authors_org %>% 
  mutate(pre = str_sub(text_clean, 1, 2)) %>% 
  relocate(pre, .before = text_clean) 

# Remove residual noise (position verbs, etc)

liuri_authors_org <- liuri_authors_org %>% 
  mutate(text_clean = str_replace(text_clean, "任", ""))%>% 
  mutate(text_clean = str_replace(text_clean, "入", ""))%>% 
  mutate(text_clean = str_replace(text_clean, "久", ""))%>% 
  mutate(text_clean = str_replace(text_clean, "于", ""))%>% 
  mutate(text_clean = str_replace(text_clean, "於", ""))%>% 
  mutate(text_clean =  str_replace(text_clean, "從", "")) %>% 
  mutate(length = nchar(text_clean)) %>% 
  filter(length > 1) %>% # 
  mutate(pre = str_sub(text_clean, 1, 2)) 

liuri_authors_org <- liuri_authors_org %>% 
  filter(stringr::str_detect(liuri_authors_org$text_clean, "[\\p{Han}]"))

# 461 organizations remain 

Basic statistics

# Most important institutions (altogether, across biographies)

liuri_authors_org %>% group_by(text_clean) %>% 
  count(sort = TRUE) 
liuri_authors_org %>% distinct(DocId, text_clean) %>% 
  group_by(text_clean) %>% count(sort = TRUE)
# Most important types of institutions

liuri_authors_org %>% distinct(DocId, text_clean, class) %>% 
  group_by(class) %>% count(sort = TRUE)


Finally, we export the list of authors with extracted information for manual verification to remove redundant or irrelevant results. We also export the list of organizational affiliations to standardize and categorize the authors and their occupations.

write.csv(liuri_authors_org, "~/output/liuri_authors_org.csv")
write.csv(liuri_authors_bio_filtered, "~/output/liuri_authors_bio_filtered.csv")

Univariate Analyses

# Reimport curated list of authors and their attributes 

library(readr)
liuri_authors_to_analyze <- read_delim("~/liuri_authors_to_analyze.csv", 
                                       delim = ";", escape_double = FALSE, trim_ws = TRUE)

# Replace empty fields with NAs

liuri_authors_to_analyze <-liuri_authors_to_analyze %>% 
  mutate(across(everything(), ~ifelse(.=="", NA, as.character(.))))
liuri_authors_to_analyze

Nationality

liuri_authors_to_analyze %>% group_by(Nationality) %>% count(sort = TRUE) 

Generation

liuri_authors_to_analyze %>% group_by(Generation) %>% count()
library(hrbrthemes)
library(viridis)

liuri_authors_to_analyze %>% drop_na(BirthYear) %>% 
  mutate(BirthYear = as.numeric(BirthYear))%>% 
  ggplot( aes(x=BirthYear)) +
  geom_histogram( binwidth=1, fill="#69b3a2", color="#e9ecef", alpha=0.9) +
  ggtitle("Bin size = 1") +
  theme_ipsum() +
  theme(
    plot.title = element_text(size=15)
  ) +
  labs(title = "Authors' Year of Birth (留日)",
       x = "Year",
       y = "Frequency")

### Native Place

liuri_authors_to_analyze %>% group_by(Birthplace) %>% count(sort = TRUE)

Country of education

liuri_authors_to_analyze %>% group_by('Country of Education') %>% count(sort = TRUE)
liuri_authors_to_analyze %>% group_by('Education Country') %>% count(sort = TRUE)

Professional background

liuri_authors_to_analyze %>% group_by(Occupation) %>% count(sort = TRUE)
liuri_authors_to_analyze %>% group_by(Occupation2) %>% count(sort = TRUE)
liuri_authors_to_analyze %>% group_by(Specialization) %>% count(sort = TRUE)

Political Affiliation

liuri_authors_to_analyze %>% group_by(Party) %>% count(sort = TRUE)


Note: DL = Democratic League. GMD = Guomindang. TMH = Tongmenghui.

Multiple Correspondance Analysis (MCA)

In the final section, we employed Multiple Correspondence Analysis (MCA)—a statistical method used to identify correlations between categorical attributes and to cluster individuals with similar profiles. This analysis aims to examine how biographical factors—generation, native place, education, and occupation—correlate with the topics authors engaged with and the overall sentiment (positive or negative) they expressed toward Japanese- and American-returned students.

Data Preparation

liuri_mca <- liuri_authors_to_analyze %>% select(Name, Generation, 'Education Country', Occupation, Sentiment, Topic)
liuri_mca <-  liuri_mca %>% drop_na(Generation) # 38 remain
liuri_mca <- column_to_rownames(liuri_mca, "Name")
liuri_mca

MCA

library(FactoMineR)
res.MCA<-MCA(liuri_mca,graph=FALSE)
# Plot 

plot.MCA(res.MCA, choix='var',title="Category Plot (留日)",col.var=c(1,2,3,4,5))

plot.MCA(res.MCA,col.var=c(1,1,2,2,2,2,3,3,3,3,3,3,4,4,5,5,5,5,5),title="Biplot (留日)", cex=0.8,cex.main=0.8,cex.axis=0.8, autoLab = "yes", label =c('ind','var'))

plot.MCA(res.MCA,invisible= 'ind',col.var=c(1,1,2,2,2,2,3,3,3,3,3,3,4,4,5,5,5,5,5),title="Biplot: Variables (留日)", label =c('var'))

plot.MCA(res.MCA,invisible= 'var',title="Biplot: Individuals (留日)", autoLab = "yes", label =c('ind'))

# Statistics

dimdesc(res.MCA)
## $`Dim 1`
## 
## Link between the variable and the categorical variable (1-way anova)
## =============================================
##                          R2      p.value
## Occupation        0.7709533 2.148266e-09
## Sentiment         0.4218280 1.024995e-05
## Topic             0.5135315 6.499835e-05
## Education Country 0.3818629 8.607131e-04
## 
## Link between variable and the categories of the categorical variables
## ================================================================
##                                         Estimate      p.value
## Occupation=official-bureaucrat         1.1633233 4.228327e-08
## Sentiment=Negative                     0.4203240 1.024995e-05
## Education Country=Japan-USA            1.1050754 3.762293e-04
## Topic=T1. Sino-Japanese Tensions       0.4902976 2.864683e-03
## Topic=T3. Regulations/Petitions        0.6574203 1.252314e-02
## Occupation=Occupation.NA              -0.5183219 4.802206e-02
## Occupation=scholar                    -0.5934239 4.345915e-02
## Education Country=China-NA            -0.6037227 8.390405e-03
## Topic=T2. Education/Political Reforms -0.6425274 6.407185e-03
## Sentiment=Positive                    -0.4203240 1.024995e-05
## 
## $`Dim 2`
## 
## Link between the variable and the categorical variable (1-way anova)
## =============================================
##                          R2      p.value
## Education Country 0.7093506 3.052458e-09
## Occupation        0.6645913 7.827675e-07
## Topic             0.4276463 8.083377e-04
## Generation        0.1771280 8.508663e-03
## 
## Link between variable and the categories of the categorical variables
## ================================================================
##                                         Estimate      p.value
## Education Country=USA                  1.1169567 1.395572e-09
## Occupation=scholar                     0.3925588 1.557418e-04
## Occupation=other                       1.7668460 1.222569e-03
## Topic=T5. Science/Society              0.4605570 2.113793e-03
## Generation=Post1895                    0.2680503 8.508663e-03
## Occupation=Occupation.NA              -0.4671254 2.311983e-02
## Topic=T2. Education/Political Reforms -0.4208162 2.127080e-02
## Generation=Pre1895                    -0.2680503 8.508663e-03
## Education Country=China-NA            -0.4651175 1.757432e-04
## 
## $`Dim 3`
## 
## Link between the variable and the categorical variable (1-way anova)
## =============================================
##                          R2      p.value
## Occupation        0.7525211 7.167313e-09
## Education Country 0.4959088 3.014586e-05
## Generation        0.2287223 2.389528e-03
## Sentiment         0.1555015 1.429194e-02
## Topic             0.2855281 2.225784e-02
## 
## Link between variable and the categories of the categorical variables
## ================================================================
##                                   Estimate      p.value
## Education Country=Japan-USA      0.9837227 0.0007376626
## Occupation=official-bureaucrat   0.8010895 0.0017044975
## Generation=Pre1895               0.2978747 0.0023895278
## Education Country=Japan          0.1281767 0.0129134879
## Sentiment=Positive               0.2445848 0.0142919370
## Topic=T5. Science/Society        0.4540580 0.0188378544
## Occupation=scholar-official      1.3086641 0.0220182770
## Occupation=scholar               0.2613957 0.0266810092
## Occupation=professional writer  -0.5554794 0.0449019649
## Topic=T3. Regulations/Petitions -0.4946911 0.0339162669
## Occupation=other                -1.4185423 0.0295543993
## Sentiment=Negative              -0.2445848 0.0142919370
## Occupation=Occupation.NA        -0.3971275 0.0119155003
## Generation=Post1895             -0.2978747 0.0023895278
## Education Country=China-NA      -0.6437582 0.0006121810

Hierarchical Clustering

Finally, hierarchical clustering is applied to categorize authors based on shared characteristics:

res.MCA<-MCA(liuri_mca,ncp=14,graph=FALSE)
res.HCPC<-HCPC(res.MCA,nb.clust=5,consol=FALSE,graph=FALSE)
# Plots

plot.HCPC(res.HCPC,choice='tree',title='Tree Map (留日)')

plot.HCPC(res.HCPC,choice='map',draw.tree=FALSE,title='Factor Map (留日)')

plot.HCPC(res.HCPC,choice='3D.map',ind.names=FALSE,centers.plot=FALSE,angle=60,title='3D-Tree Map (留日)')

# Statistics

summary(res.HCPC)
##            Length Class      Mode
## data.clust 6      data.frame list
## desc.var   3      catdes     list
## desc.axes  3      catdes     list
## desc.ind   2      -none-     list
## call       7      -none-     list

Going Further

For a comparative perspective, please consult the corresponding scripts on American-returned students.