I have been told that it would be wise to split up my code into semantically useful blocks. I tried the following but I need feedback.
What I already did:
- As you can see I create two .csv files, so it seemed logical to have two functions. One for the main dataset, the other for a frequency table
- I only import modules where I need them, though I did need some globally.
I probably should give fn
, c
and s
better variable names. However, I'm not sure how to name them because they are identical to the column names they will be assigned to (e.g. node = node, sentence = sentence).
So what else can I do to better format my code into useful functions? Do note that I want to put an emphasis on performance, so any edits that decrease performance are discouraged.
import os, pandas as pd, numpy as np
from datetime import datetime
start_time = datetime.now()
# Create empty dataframe with correct column names
column_names = ["fileName", "component", "precedingWord", "node", "leftContext", "sentence" ]
df = pd.DataFrame(data=np.zeros((0, len(column_names))), columns=column_names)
# Create correct path where to fetch files
subdir = "rawdata"
path = os.path.abspath(os.path.join(os.getcwd(), os.pardir, subdir))
def main_dataset():
import regex as re
from html import unescape
# Loop files in folder
filenames = [name for name in os.listdir(path) if re.match(".*?[.]lst", name)]
# "Cache" regex
# See http://stackoverflow.com/q/452104/1150683
p_filename = re.compile(r"[./\\]")
p_sentence = re.compile(r"<sentence>(.*?)</sentence>")
p_typography = re.compile(r" (?:(?=[.,:;?!) ])|(?<=\( ))")
p_non_graph = re.compile(r"[^\x21-\x7E\s]")
p_quote = re.compile(r"\"")
p_ellipsis = re.compile(r"\.{3}(?=[^ ])")
p_last_word = re.compile(r"^.*\b(?<!-)(\w+(?:-\w+)*)[^\w]*$", re.U)
fn_list = []
c_list = []
pw_list = []
n_list = []
lc_list = []
s_list = []
for filename in filenames:
with open(path + '/' + filename, 'r+', encoding="utf-8") as f:
[n, c] = p_filename.split(filename.lower())[-3:-1]
fn = ".".join([n, c])
for line in f:
s = p_sentence.search(unescape(line)).group(1)
s = s.lower()
s = p_typography.sub("", s)
s = p_non_graph.sub("", s)
s = p_quote.sub("'", s)
s = p_ellipsis.sub("... ", s)
if n in re.split(r"[ :?.,]", s):
lc = re.split(r"(^| )" + n + "( |[!\",.:;?})\]])", s)[0]
pw = p_last_word.sub("\\1", lc)
fn_list.append(fn)
c_list.append(c)
pw_list.append(pw)
n_list.append(n)
lc_list.append(lc)
s_list.append(s)
continue
# Assign data frame
df['fileName'] = fn_list
df['component'] = c_list
df['precedingWord'] = pw_list
df['node'] = n_list
df['leftContext'] = lc_list
df['sentence'] = s_list
# Reset indices
df.reset_index(drop=True, inplace=True)
# Export dataset
df.to_csv("dataset/py-dataset.csv", sep="\t", encoding="utf-8")
def frequency_table():
# Define neuter and non_neuter
neuter = ["het"]
non_neuter = ["de"]
# Create crosstab
df.loc[df.precedingWord.isin(neuter), "gender"] = "neuter"
df.loc[df.precedingWord.isin(non_neuter), "gender"] = "non_neuter"
df.loc[df.precedingWord.isin(neuter + non_neuter) == 0, "gender"] = "rest"
freqDf = pd.crosstab(df.node, df.gender)
freqDf.to_csv("dataset/py-frequencies.csv", sep="\t", encoding="utf-8")
# How long has the script been running?
time_difference = datetime.now() - start_time
print("Time difference of", time_difference)
main_dataset()
frequency_table()