text:
Functional load is a measure of the “work” that any particular contrast does in a language, as compared to other contrasts (e.g., [Hockett1955], [Hockett1966]; [Kucera1963]; [King1967]; [Surendran2003]). Two contrasts in a language, such as [d] / [t] vs. [ð] / [θ] in English, may have very different functional loads. The difference between [d] and [t] is used to distinguish between many different lexical items, so it has a high functional load; there are, on the other hand, very few lexical items that hinge on the distinction between [ð] and [θ], so its functional load is much lower. One of the primary claims about functional load is that it is related to sounds’ propensity to merge over time, with pairs of sounds that have higher functional loads being less likely to merge than pairs of sounds with lower functional loads (e.g., [Wedel2013], [Todd2012]). The average functional load of a particular sound has also been claimed to affect its likelihood of being used as an epenthetic vowel [Hume2013]. Functional load has also been illustrated to affect the perceived similarity of sounds [Hall2014a].

Method of calculation¶

There are two primary ways of calculating functional load that are provided as part of the PCT package. One is based on the change of entropy in a system upon merger of a segment pair or set of segment pairs (cf. [Surendran2003]); the other is based on simply counting up the number of minimal pairs (differing in only the target segment pair or pairs) that occur in the corpus.

Change in entropy¶

The calculation based on change in entropy is described in detail in [Surendran2003]. Entropy is an Information-Theoretic measure of the amount of uncertainty in a system [Shannon1949], and is calculated using the formula in (1); it will also be used for the calculation of predictability of distribution (see Method of calculation). For every symbol i in some inventory (e.g., every phoneme in the phoneme inventory, or every word in the lexicon), one multiplies the probability of i by the $$log_{2}$$ of the probability of i; the entropy is the sum of the products for all symbols in the inventory.

Entropy:

$$H = -\sum_{i \in N} p_{i} * log_{2}(p_{i})$$

The functional load of any pair of sounds in the system, then, can be calculated by first calculating the entropy of the system at some level of structure (e.g., words, syllables) with all sounds included, then merging the pair of sounds in question and re-calculating the entropy of the new system. That is, the functional load is the amount of uncertainty (entropy) that is lost by the merger. If the pair has a functional load of 0, then nothing has changed when the two are merged, and $$H_{1}$$ will equal $$H_{2}$$. If the pair has a non-zero functional load, then the total inventory has become smaller through the conflating of pairs of symbols that were distinguished only through the given pair of sounds.

Functional load as change in entropy:

$$\Delta H = H_{1} - H_{2}$$

Consider a toy example, in which the following corpus is assumed (note that, generally speaking, there is no “type frequency” column in a PCT corpus, as it is assumed that each row in the corpus represents 1 type; it is included here for clarity):

Consider a toy example, in which the following corpus is assumed (note that, generally speaking, there is no “type frequency” column in a PCT corpus, as it is assumed that each row in the corpus represents 1 type; it is included here for clarity):

Word Original Under [h] / [ŋ] merger Under [t] / [d] merger
Trans. Type Freq. Token Freq. Trans. Type Freq. Token Freq. Trans. Type Freq. Token Freq.
hot [hɑt] 1 2 [Xɑt] 1 2 [hɑX] 1 2
song [sɑŋ] 1 4 [sɑX] 1 4 [sɑŋ] 1 4
hat [hæt] 1 1 [Xæt] 1 1 [hæX] 1 1
sing [sɪŋ] 1 6 [sɪX] 1 6 [sɪŋ] 1 6
tot [tɑt] 1 3 [tɑt] 1 3 [XɑX] 1 8
dot [dɑt] 1 5 [dɑt] 1 5 [XɑX]
hip [hɪp] 1 2 [Xɪp] 1 2 [hɪp] 1 2
hid [hɪd] 1 7 [Xɪd] 1 7 [hɪX] 1 7
team [tim] 1 5 [tim] 1 5 [Xim] 1 10
deem [dim] 1 5 [dim] 1 5 [Xim]
toot [tut] 1 9 [tut] 1 9 [XuX] 1 11
dude [dud] 1 2 [dud] 1 2 [XuX]
hiss [hɪs] 1 3 [Xɪs] 1 3 [hɪs] 1 3
his [hɪz] 1 5 [Xɪz] 1 5 [hɪz] 1 5
sizzle [sɪzəl] 1 4 [sɪzəl] 1 4 [sɪzəl] 1 4
dizzy [dɪzi] 1 3 [dɪzi] 1 3 [Xɪzi] 1 7
tizzy [tɪzi] 1 4 [tɪzi] 1 4 [Xɪzi]
Total 17 70   17 70   13 70

The starting entropy, assuming word types as the relative unit of structure and counting, is:

$$H_{1 - types} = -[(\frac{1}{17} log_{2}(\frac{1}{17})) + (\frac{1}{17} log_{2}(\frac{1}{17})) + (\frac{1}{17} log_{2}(\frac{1}{17})) + (\frac{1}{17} log_{2}(\frac{1}{17})) + (\frac{1}{17} log_{2}(\frac{1}{17}))\\ + (\frac{1}{17} log_{2}(\frac{1}{17})) + (\frac{1}{17} log_{2}(\frac{1}{17})) + (\frac{1}{17} log_{2}(\frac{1}{17})) + (\frac{1}{17} log_{2}(\frac{1}{17})) + (\frac{1}{17} log_{2}(\frac{1}{17})) + (\frac{1}{17} log_{2}(\frac{1}{17}))\\ + (\frac{1}{17} log_{2}(\frac{1}{17})) + (\frac{1}{17} log_{2}(\frac{1}{17})) + (\frac{1}{17} log_{2}(\frac{1}{17})) + (\frac{1}{17} log_{2}(\frac{1}{17})) + (\frac{1}{17} log_{2}(\frac{1}{17})) + (\frac{1}{17} log_{2}(\frac{1}{17}))] =4.087$$

The starting entropy, assuming word tokens, is:

$$H_{1 - tokens} = -[(\frac{2}{70} log_{2}(\frac{2}{70})) + (\frac{4}{70} log_{2}(\frac{4}{70})) + (\frac{1}{70} log_{2}(\frac{1}{70})) + (\frac{6}{70} log_{2}(\frac{6}{70})) + (\frac{3}{70} log_{2}(\frac{3}{70}))\\ + (\frac{5}{70} log_{2}(\frac{5}{70})) + (\frac{2}{70} log_{2}(\frac{2}{70})) + (\frac{7}{70} log_{2}(\frac{7}{70})) + (\frac{5}{70} log_{2}(\frac{5}{70})) + (\frac{5}{70} log_{2}(\frac{5}{70})) + (\frac{9}{70} log_{2}(\frac{9}{70}))\\ + (\frac{2}{70} log_{2}(\frac{2}{70})) + (\frac{3}{70} log_{2}(\frac{3}{70})) + (\frac{5}{70} log_{2}(\frac{5}{70})) + (\frac{4}{70} log_{2}(\frac{4}{70})) + (\frac{3}{70} log_{2}(\frac{3}{70})) + (\frac{4}{70} log_{2}(\frac{4}{70}))] = 3.924$$

Upon merger of [h] and [ŋ], there is no change in the number of unique words; there are still 17 unique words with all their same token frequencies. Thus, the entropy after an [h] / [ŋ] merger will be the same as it was before the merger. The functional load, then would be 0, as the pre-merger and post-merger entropies are identical.

Upon merger of [t] and [d], on the other hand, four pairs of words have been collapsed. E.g., the difference between team and deem no longer exists; there is now just one word, [Xim], where [X] represents the result of the merger. Thus, there are only 13 unique words, and while the total token frequency count remains the same, at 70, those 70 occurrences are divided among only 13 unique words instead of 17.

Thus, the entropy after a [t] / [d] merger, assuming word types, is:

$$H_{1 - types} = -[(\frac{1}{13} log_{2}(\frac{1}{13})) + (\frac{1}{13} log_{2}(\frac{1}{13})) + (\frac{1}{13} log_{2}(\frac{1}{13})) + (\frac{1}{13} log_{2}(\frac{1}{13})) + (\frac{1}{13} log_{2}(\frac{1}{13}))\\ + (\frac{1}{13} log_{2}(\frac{1}{13})) + (\frac{1}{13} log_{2}(\frac{1}{13})) + (\frac{1}{13} log_{2}(\frac{1}{13})) + (\frac{1}{13} log_{2}(\frac{1}{13})) + (\frac{1}{13} log_{2}(\frac{1}{13})) + (\frac{1}{13} log_{2}(\frac{1}{13}))\\ + (\frac{1}{13} log_{2}(\frac{1}{13})) + (\frac{1}{13} log_{2}(\frac{1}{13}))] = 3.700$$

And the entropy after a [t] / [d] merger, assuming word tokens, is:

$$H_{1 - tokens} = -[(\frac{2}{70} log_{2}(\frac{2}{70})) + (\frac{4}{70} log_{2}(\frac{4}{70})) + (\frac{1}{70} log_{2}(\frac{1}{70})) + (\frac{6}{70} log_{2}(\frac{6}{70})) + (\frac{8}{70} log_{2}(\frac{8}{70}))\\ + (\frac{2}{70} log_{2}(\frac{2}{70})) + (\frac{7}{70} log_{2}(\frac{7}{70})) + (\frac{10}{70} log_{2}(\frac{10}{70})) + (\frac{11}{70} log_{2}(\frac{11}{70})) + (\frac{3}{70} log_{2}(\frac{3}{70})) + (\frac{5}{70} log_{2}(\frac{5}{70}))\\ + (\frac{4}{70} log_{2}(\frac{4}{70})) + (\frac{7}{70} log_{2}(\frac{7}{70}))] = 3.466$$

$$\Delta H = H_{1-types} - H_{2-types} = 4.087– 3.700 = 0.387$$

And the functional load of [t] / [d] based on word tokens is:

$$\Delta H = H_{1-tokens} - H_{2-tokens} = 3.924– 3.466 = 0.458$$

(Relative) Minimal Pair Counts¶

The second means of calculating functional load that is included in PCT is a straight count of minimal pairs, which can be relativized to the number of words in the corpus that are potential minimal pairs—i.e. the number of words in the corpus with at least one of the target segments.

In the above example, the number of minimal pairs that hinge on [h] vs. [ŋ] is of course 0, so the functional load of [h] / [ŋ] is 0. The number of minimal pairs that hinge on [t] / [d] is 3, and the number of words with either [t] or [d] is 11; the functional load as a relativized minimal pair count would therefore be 3/11 = 0.273. Note that here, a relatively loose definition of minimal pair is used; specifically, two words are considered to be a minimal pair hinging on sounds A and B if, upon merger of A and B into a single symbol X, the words are identical. Thus, toot and dude are considered a minimal pair on this definition, because they both become [XuX] upon merger of [t] and [d].

The resulting calculations of functional load are thus quite similar between the two measures, but the units are entirely different. Functional load based on change in entropy is measured in bits, while functional load based on relativized minimal pair counts is simply a percentage. Also note that functional load based on minimal pairs is only based on type frequency; the frequency of the usage of the words is not used as a weighting factor, the way it can be under the calculation of functional load as change in entropy.

[Hume2013] suggests that the average functional load (there called “relative contrastiveness”) is a useful way of indicating how much work an individual segment does, on average, in comparison to other segments. This is calculated by taking an individual segment, calculating the pairwise functional load of that segment and each other segment in the inventory, and then taking the average across all those pairs. This calculation can also be performed in PCT.

Calculating functional load in the GUI¶

As with most analysis functions, a corpus must first be loaded (see Loading in corpora). Once a corpus is loaded, use the following steps.

1. Getting started: Choose “Analysis” / “Calculate functional load...” from the top menu bar.

2. Sound selection: First, decide whether you want to calculate the average functional load of a single segment (i.e., its functional load averaged across all possible pairwise comparisons), or the more standard functional load of a pair of sounds, defined over segments or features. To calculate the average functional load of a single sound, choose “Add one segment”; to calculate the pairwise functional load of two segments, choose “Add pair of segments”; to calculate the pairwise functional load based on features, choose “Add pair of features.”

For details on how to actually select segments or features, see Sound Selection or Feature Selection as relevant.

When multiple individual segments or individual pairs are selected, each entry will be treated separately.

3. Functional load algorithm: Select which of the two methods of calculation you want to use—i.e., minimal pairs or change in entropy. (See discussion above for details of each.)

4. Minimal pair options: If minimal pairs serve as the means of calculation, there are three additional parameters can be set.

1. Raw vs. relative count: First, PCT can report only the raw count of minimal pairs that hinge on the contrast in the corpus, if you just want to know the scope of the contrast. On the other hand, the default is to relativize the raw count to the corpus size, by dividing the raw number by the number of lexical entries that include at least one instance of any of the target segments.
2. Include vs. ignore homophones: Second, PCT can either include homophones or ignore them. For example, if the corpus includes separate entries for the words sock (n.), sock (v.), shock (n.), and shock (v.), this would count as four minimal pairs if homophones are included, but only one if homophones are ignored. The default is to ignore homophones.
3. Output list of minimal pairs to a file: It is possible to save a list of all the actual minimal pairs that PCT finds that hinge on a particular chosen contrast to a .txt file. To do so, enter a file path name, or select “Choose file...” to use a regular system dialogue box. If nothing is entered here, no list will be saved, but the overall output will still be provided (and can be saved independently).
5. Change in entropy options: If you are calculating functional load using change in entropy, one additional parameter can be set.

1. Type or token frequency: As described in Change in entropy, entropy can be calculated using either type or token frequencies. This option determines which to use.
6. Tier: Select which tier the functional load should be calculated from. The default is the “transcription” tier, i.e., looking at the entire word transcriptions. If another tier has been created (see Creating new tiers in the corpus), functional load can be calculated on the basis of that tier. For example, if a vowel tier has been created, then “minimal pairs” will be entries that are identical except for one entry in the vowels only, entirely independently of consonants. Thus, the words [mapotik] and [ʃɹaɡefli] would be treated as a minimal pair, given that their vowel-tier representations are [aoi] and [aei].

7. Pronunciation variants: If the corpus contains multiple pronunciation variants for lexical items, select what strategy should be used. For details, see Pronunciation Variants.

8. Minimum frequency: It is possible to set a minimum token frequency for words in the corpus in order to be included in the calculation. This allows easy exclusion of rare words; for example, if one were calculating the functional load of [s] vs. [ʃ] in English and didn’t set a minimum frequency, words such as santy (vs. shanty) might be included, which might not be a particularly accurate reflection of the phonological knowledge of speakers. To include all words in the corpus, regardless of their token frequency, set the the minimum frequency to 0.

Here is an example of selecting [m] and [n], with functional load to be calculated on the basis of minimal pairs, only including words with a token frequency of at least 1, from the built-in example corpus (which only has canonical forms):

1. Results: Once all parameters have been set, click one of the two “Calculate functional load” buttons. If this is the first calculation, the option to “start new results table” should be selected. For subsequent calculations, the calculation can be added to the already started table, for direct comparison, or a new table can be started.
Note that if a table is closed, new calculations will not be added to the previously
open table; a new table must be started.

Either way, the results table will have the following columns, with one row per calculation: segment 1, segment 2, which tier was used, what environments were selected, which measurement method was selected, the resulting functional load, what the minimum frequency was, what strategy was used for dealing with pronunciation variants, and for calculations using minimal pairs, whether the count is absolute or relative and whether homophones were distinguished or not. (For calculations using change in entropy, “N/A” values are entered into the latter two columns.)

1. Saving results: Once a results table has been generated for at least one pair, the table can be saved by clicking on “Save to file” at the bottom of the table to open a system dialogue box and save the results at a user-designated location.

Note

that in the above screen shot, not all columns are visible; they are visible only by scrolling over to the right, due to constraints on the window size. All columns would be saved to the results file.)

To return to the function dialogue box with your most recently used selections, click on “Reopen function dialog.” Otherwise, the results table can be closed and you will be returned to your corpus view.

Implementing the functional load function on the command line¶

In order to perform this analysis on the command line, you must enter a command in the following format into your Terminal:

pct_funcload CORPUSFILE [additional arguments]

...where CORPUSFILE is the name of your *.corpus file. If calculating FL from a file of segment pairs, it must list the pairs of segments whose functional load you wish to calculate with each pair separated by a tab (\t) and one pair on each line. Note that you must either specify a file or segment (using -p) or request the functional loads of all segment pairs in the inventory (using -l). You may also use command line options to change various parameters of your functional load calculations. Descriptions of these arguments can be viewed by running pct_funcload –h or pct_funcload --help. The help text from this command is copied below, augmented with specifications of default values:

Positional arguments:

corpus_file_name

Name of corpus file

Mandatory argument group (call must have one of these two):

-p PAIRS_FILE_NAME_OR_SEGMENT
--pairs_file_name_or_segment PAIRS_FILE_NAME_OR_SEGMENT

Name of file with segment pairs (or target segment if relative fl is True)

-l
--all_pairwise_fls

Flag: calculate FL for all pairs of segments

Optional arguments:

-h
--help

Show help message and exit

-c CONTEXT_TYPE
--context_type CONTEXT_TYPE

How to deal with variable pronunciations. Options are ‘Canonical’, ‘MostFrequent’, ‘SeparatedTokens’, or ‘Weighted’. See documentation for details.

-a ALGORITHM
--algorithm ALGORITHM

Algorithm to use for calculating functional load: “minpair” for minimal pair count or “deltah” for change in entropy. Defaults to minpair.

-f FREQUENCY_CUTOFF
--frequency_cutoff FREQUENCY_CUTOFF

Minimum frequency of words to consider as possible minimal pairs or contributing to lexicon entropy.

-d DISTINGUISH_HOMOPHONES
--distinguish_homophones DISTINGUISH_HOMOPHONES

For minimal pair FL: if False, then you’ll count sock~shock (sock=clothing) and sock~shock (sock=punch) as just one minimal pair; but if True, you’ll overcount alternative spellings of the same word, e.g. axel~actual and axle~actual. False is the value used by Wedel et al.

-t TYPE_OR_TOKEN
--type_or_token TYPE_OR_TOKEN

For change in entropy FL: specifies whether entropy is based on type or token frequency.

-e RELATIVE_FL
--relative_fl RELATIVE_FL

If True, calculate the relative FL of a single segment by averaging across the functional loads of it and all other segments.

-s SEQUENCE_TYPE
--sequence_type SEQUENCE_TYPE

The attribute of Words to calculate FL over. Normally this will be the transcription, but it can also be the spelling or a user-specified tier.

-o OUTFILE
--outfile OUTFILE

Name of output file

EXAMPLE 1: If your corpus file is example.corpus (no prounciation variants) and you want to calculate the minimal pair functional load of the segments [m] and [n] using defaults for all optional arguments, you first need to create a text file that contains the text m\tn (where \t is a tab). Let us call this file pairs.txt. You would then run the following command in your terminal window:

pct_funcload example.corpus -p pairs.txt

EXAMPLE 2: Suppose you want to calculate the relative (average) functional load of the segment [m]. Your corpus file is again example.corpus. You want to use the change in entropy measure of functional load rather than the minimal pairs measure, and you also want to use type frequency instead of (the default value of) token frequency. In addition, you want the script to produce an output file called output.txt. You would need to run the following command:

pct_funcload example.corpus -p m -e -a deltah -t type -o output.txt

EXAMPLE 3: Suppose you want to calculate the functional loads of all segment pairs. Your corpus file is again example.corpus. All other parameters are set to defaults. In addition, you want the script to produce an output file called output.txt. You would need to run the following command:

pct_funcload example.corpus -l -o output.txt

Classes and functions¶

For further details about the relevant classes and functions in PCT’s source code, please refer to Functional load.


text:
# Estimating $b_1 x_1+b_2 x_2$ instead of $b_1 x_1+b_2 x_2+b_3x_3$

I have a theoretical economic model which is as follows,

$$y = a + b_1x_1 + b_2x_2 + b_3x_3 + u$$

So theory says that there are $x_1$, $x_2$ and $x_3$ factors to estimate $y$.

Now I have the real data and I need to estimate $b_1$, $b_2$, $b_3$. The problem is that the real data set contains only data for $x_1$ and $x_2$; there are no data for $x_3$. So the model I can fit actually is:

$$y = a + b_1x_1 + b_2x_2 + u$$

• Is it OK to estimate this model?
• Do I lose anything estimating it?
• If I do estimate $b_1$, $b_2$, then where does the $b_3x_3$ term go?
• Is it accounted for by error term $u$?

And we would like to assume that $x_3$ is not correlated with $x_1$ and $x_2$.

• Can you give details about your data set, I mean, your dependent variable $y$ and independent variables $x_1$ and $x_2$? – Vara May 11 '13 at 14:32
• Think of it as hypothethical example without specific data set... – renathy May 11 '13 at 15:05

The issue you need to worry about is called endogeneity. More specifically, it depends on whether $x_3$ is correlated in the population with $x_1$ or $x_2$. If it is, then the associated $b_j$s will be biased. That is because OLS regression methods force the residuals, $u_i$, to be uncorrelated with your covariates, $x_j$s. However, your residuals are composed of some irreducible randomness, $\varepsilon_i$, and the unobserved (but relevant) variable, $x_3$, which by stipulation is correlated with $x_1$ and / or $x_2$. On the other hand, if both $x_1$ and $x_2$ are uncorrelated with $x_3$ in the population, then their $b$s won't be biased by this (they may well be biased by something else, of course). One way econometricians try to deal with this issue is by using instrumental variables.

For the sake of greater clarity, I've written a quick simulation in R that demonstrates the sampling distribution of $b_2$ is unbiased / centered on the true value of $\beta_2$, when it is uncorrelated with $x_3$. In the second run, however, note that $x_3$ is uncorrelated with $x_1$, but not $x_2$. Not coincidentally, $b_1$ is unbiased, but $b_2$ is biased.

library(MASS)                          # you'll need this package below
N     = 100                            # this is how much data we'll use
beta0 = -71                            # these are the true values of the
beta1 = .84                            # parameters
beta2 = .64
beta3 = .34

############## uncorrelated version

b0VectU = vector(length=10000)         # these will store the parameter
b1VectU = vector(length=10000)         # estimates
b2VectU = vector(length=10000)
set.seed(7508)                         # this makes the simulation reproducible

for(i in 1:10000){                     # we'll do this 10k times
x1 = rnorm(N)
x2 = rnorm(N)                        # these variables are uncorrelated
x3 = rnorm(N)
y  = beta0 + beta1*x1 + beta2*x2 + beta3*x3 + rnorm(100)
mod = lm(y~x1+x2)                    # note all 3 variables are relevant
# but the model omits x3
b0VectU[i] = coef(mod)[1]            # here I'm storing the estimates
b1VectU[i] = coef(mod)[2]
b2VectU[i] = coef(mod)[3]
}
mean(b0VectU)  # [1] -71.00005         # all 3 of these are centered on the
mean(b1VectU)  # [1] 0.8399306         # the true values / are unbiased
mean(b2VectU)  # [1] 0.6398391         # e.g., .64 = .64

############## correlated version

r23 = .7                               # this will be the correlation in the
b0VectC = vector(length=10000)         # population between x2 & x3
b1VectC = vector(length=10000)
b2VectC = vector(length=10000)
set.seed(2734)

for(i in 1:10000){
x1 = rnorm(N)
X  = mvrnorm(N, mu=c(0,0), Sigma=rbind(c(  1, r23),
c(r23,   1)))
x2 = X[,1]
x3 = X[,2]                           # x3 is correated w/ x2, but not x1
y  = beta0 + beta1*x1 + beta2*x2 + beta3*x3 + rnorm(100)
# once again, all 3 variables are relevant
mod = lm(y~x1+x2)                    # but the model omits x3
b0VectC[i] = coef(mod)[1]
b1VectC[i] = coef(mod)[2]            # we store the estimates again
b2VectC[i] = coef(mod)[3]
}
mean(b0VectC)  # [1] -70.99916         # the 1st 2 are unbiased
mean(b1VectC)  # [1] 0.8409656         # but the sampling dist of x2 is biased
mean(b2VectC)  # [1] 0.8784184         # .88 not equal to .64

• So, can you explain a bit more - what happens if we assume that $x_3$ is not correlated with $x_1$ and $x_2$? Then what happens if I estimate $y=a+b_1x_1+b_2x_2+u$? – renathy May 11 '13 at 15:04
• $b_3x_3$ will be incorporated into the residuals either way, but if it is uncorrelated in the population, then your other $b$s won't be biased by the absence of $x_3$, but if it's not uncorrelated, then they will be. – gung - Reinstate Monica May 11 '13 at 15:08
• To state this more clearly: If $x_3$ is not correlated with either $x_1$ or $x_2$, you are OK. – gung - Reinstate Monica May 11 '13 at 15:10
• I discuss the flip side of this issue in my answer here: Does adding more variables into a multivariable regression change coefficients of existing variables? – gung - Reinstate Monica Sep 18 '14 at 0:24

Let's think of this in geometric terms. Think of a "ball", the surface of a ball. It is described as $r^2 = ax^2+by^2+cz^2 + \epsilon$. Now if you have the values for $x^2$, $y^2$, $z^2$, and you have measurements of $r^2$ then you can determine your coefficients "a", "b", and "c". (You could call it ellipsoid, but to call it a ball is simpler.)

If you have only the $x^2$, and $y^2$ terms then you can make a circle. Instead of defining the surface of a ball, you will describe a filled in circle. The equation you instead fit is $r^2 \le ax^2 + by^2 + \epsilon$.

You are projecting the "ball", whatever shape it is, into the expression for the circle. It could be a diagonally oriented "ball" that is shaped more like a sewing needle, and so the $z$ components utterly wreck the estimates of the two axes. It could be a ball that looks like a nearly crushed m&m where the coin-axes are "x" and "y", and there is zero projection. You can't know which it is without the "$z$" information.

That last paragraph was talking about a "pure information" case and didn't account for the noise. Real world measurements have the signal with noise. The noise along the perimeter that is aligned to the axes is going to have a much stronger impact on your fit. Even though you have the same number of samples, you are going to have more uncertainty in your parameter estimates. If it is a different equation than this simple linear axis-oriented case, then things can go "pear shaped". Your current equations are plane-shaped, so instead of having a bound (the surface of the ball), the z-data might just go all over the map - projection could be a serious problem.

Is it okay to model? That is a judgment call. An expert who understands the particulars of the problem might answer that. I don't know if someone can give a good answer if they are far from the problem.

You do lose several good things, including certainty in parameter estimates, and the nature of the model being transformed.

The estimate for $b_3$ disappears into epsilon and into the other parameter estimates. It is subsumed by the whole equation, depending on the underlying system.

• I can't really follow your argument here, & I'm not sure if it's correct. E.g., the surface area of a sphere is $4\pi r^2$. Beyond that, I'm not sure how this relates to the question. The key issue is whether or not the omitted variable is correlated w/ variables that are in the model. I'm not sure how what you are saying addresses that issue. (For clarity, I demonstrate this with a simple R simulation.) – gung - Reinstate Monica May 11 '13 at 23:08
• Gung. I gave a best-case answer sphere -> circle and showed that it changed the model in unexpected ways. I liked the technical sophistication of your answer, but am not convinced that the asker is able to use either of our answers. the $f(x,y,z)$ is the equation for the surface of an ellipsoid in 3 dimensions, a sphere is one case of it. I am assuming that the "true model" is the surface of the sphere, but noise corrupted measurements are on the surface. Throwing out one dimension gives data that, at best, makes a filled circle instead of the surface of a sphere. – EngrStudent May 12 '13 at 4:55
• I am unable to follow your argument because I don't see anything that corresponds to a "filled in square." – whuber Sep 3 '18 at 20:19

The other answers, while not wrong, over complicate the issue a bit.

If $x_3$ is truly uncorrelated with $x_1$ and $x_2$ (and the true relationship is as specified) then you can estimate your second equation without an issue. As you suggest, $\beta_3 x_3$ will be absorbed by the (new) error term. The OLS estimates will be unbiased, as long as all the other OLS assumptions hold.

format: plain


text:
×

# Problems!

1. Let $$H$$ be the orthocenter of triangle $$ABC$$. Prove that, if $$\dfrac{AH}{BC}=\dfrac{BH}{CA}=\dfrac{CH}{AB}$$, the triangle is equilateral.

2. Let $$a, b, c$$ be the roots of $$x^3-x^2-x-1$$. Prove that $$\dfrac{a^{2014}-b^{2014}}{a-b}+\dfrac{b^{2014}-c^{2014}}{b-c}+\dfrac{c^{2014}-a^{2014}}{c-a}$$ is an integer.

3. Let $$A$$ and $$B$$ be two subsets of $$S=\{1,...,2000\}$$ such that $$|A|\cdot|B|\ge3999$$. For a set $$X$$, let $$X-X$$ denote the set $$\{x-y|x,y\in{X}\}$$. Prove that $$(A-A)\cap(B-B)$$ is not an empty set.

Note by José Marín Guzmán
3 years, 5 months ago

MarkdownAppears as
*italics* or _italics_ italics
**bold** or __bold__ bold
- bulleted- list
• bulleted
• list
1. numbered2. list
1. numbered
2. list
Note: you must add a full line of space before and after lists for them to show up correctly
paragraph 1paragraph 2

paragraph 1

paragraph 2

[example link](https://brilliant.org)example link
> This is a quote
This is a quote
    # I indented these lines
# 4 spaces, and now they show
# up as a code block.

print "hello world"
# I indented these lines
# 4 spaces, and now they show
# up as a code block.

print "hello world"
MathAppears as
Remember to wrap math in $$...$$ or $...$ to ensure proper formatting.
2 \times 3 $$2 \times 3$$
2^{34} $$2^{34}$$
a_{i-1} $$a_{i-1}$$
\frac{2}{3} $$\frac{2}{3}$$
\sqrt{2} $$\sqrt{2}$$
\sum_{i=1}^3 $$\sum_{i=1}^3$$
\sin \theta $$\sin \theta$$
\boxed{123} $$\boxed{123}$$

Sort by:

Solution to Problem 1

$$\frac{2RcosA}{a}=\frac{2RcosB}{b}=\frac{2RcosC}{c}$$

By cosine rule,

$$\frac{b^2+c^2-a^2}{2abc}=\frac{c^2+a^2-b^2}{2abc}=\frac{a^2+b^2-c^2}{2abc}$$

Hence $$a=b=c$$

- 3 years, 5 months ago


text:
# Survival Regression¶

Often we have additional data aside from the durations, and if applicable any censorships that occurred. In the regime dataset, we have the type of government the political leader was part of, the country they were head of, and the year they were elected. Can we use this data in survival analysis?

Yes, the technique is called survival regression – the name implies we regress covariates (eg: year elected, country, etc.) against a another variable – in this case durations and lifetimes. Similar to the logic in the first part of this tutorial, we cannot use traditional methods like linear regression.

There are two popular competing techniques in survival regression: Cox’s model and Aalen’s additive model. Both models attempt to represent the hazard rate $$\lambda(t | x)$$ as a function of $$t$$ and some covariates $$x$$. In Cox’s model, the relationship is defined:

$\lambda(t | x) = b_0(t)\exp\left( b_1x_1 + ... + b_dx_d\right)$

On the other hand, Aalen’s additive model assumes the following form:

$\lambda(t | x) = b_0(t) + b_1(t)x_1 + ... + b_d(t)x_d$

Warning

This implementation is still experimental.

The estimator to fit unknown coefficients in Aalen’s additive model is located in estimators under AalenAdditiveFitter. For this exercise, we will use the regime dataset and include the categorical variables un_continent_name (eg: Asia, North America,…), the regime type (eg: monarchy, civilan,…) and the year the regime started in, start_year.

Aalen’s additive model typically does not estimate the individual $$b_i(t)$$ but instead estimates $$\int_0^t b_i(s) \; ds$$ (similar to the estimate of the hazard rate using NelsonAalenFitter above). This is important to keep in mind when analzying the output.

from lifelines import AalenAdditiveFitter

ctryname cowcode2 politycode un_region_name un_continent_name ehead leaderspellreg democracy regime start_year duration observed
Afghanistan 700 700 Southern Asia Asia Mohammad Zahir Shah Mohammad Zahir Shah.Afghanistan.1946.1952.Mona... Non-democracy Monarchy 1946 7 1
Afghanistan 700 700 Southern Asia Asia Sardar Mohammad Daoud Sardar Mohammad Daoud.Afghanistan.1953.1962.Ci... Non-democracy Civilian Dict 1953 10 1
Afghanistan 700 700 Southern Asia Asia Mohammad Zahir Shah Mohammad Zahir Shah.Afghanistan.1963.1972.Mona... Non-democracy Monarchy 1963 10 1
Afghanistan 700 700 Southern Asia Asia Sardar Mohammad Daoud Sardar Mohammad Daoud.Afghanistan.1973.1977.Ci... Non-democracy Civilian Dict 1973 5 0
Afghanistan 700 700 Southern Asia Asia Nur Mohammad Taraki Nur Mohammad Taraki.Afghanistan.1978.1978.Civi... Non-democracy Civilian Dict 1978 1 0

5 rows × 12 columns

I’m using the lovely library patsy here to create a covariance matrix from my original dataframe.

import patsy
# the '-1' term refers to not adding an intercept column (a column of all 1s).
X = patsy.dmatrix('un_continent_name + regime + start_year - 1', data, return_type='dataframe')

X.columns

['un_continent_name[Africa]',
'un_continent_name[Americas]',
'un_continent_name[Asia]',
'un_continent_name[Europe]',
'un_continent_name[Oceania]',
'regime[T.Military Dict]',
'regime[T.Mixed Dem]',
'regime[T.Monarchy]',
'regime[T.Parliamentary Dem]',
'regime[T.Presidential Dem]',
'start_year']

Below we create our fitter class. Since we did not supply an intercept column in our matrix we have included the keyword fit_intercept=True (True by default) which will append the column of ones to our matrix. (Sidenote: the intercept term, $$b_0(t)$$ in survival regression is often referred to as the baseline hazard.)

We have also included the coef_penalizer option. During the estimation, a linear regression is computed at each step. Often the regression can be unstable (due to high co-linearity or small sample sizes) – adding a penalizer term controls the stability. I recommend always starting with a small penalizer term – if the estimates still appear to be too unstable, try increasing it.

aaf = AalenAdditiveFitter(coef_penalizer=1.0, fit_intercept=True)

An instance of AalenAdditiveFitter includes a fit method that performs the inference on the coefficients. This method accepts a pandas DataFrame: each row is an individual and columns are the covariates and two special columns: a duration column and a boolean event occured column (where event occured refers to the event of interest - expulsion from government in this case)

data = lifelines.datasets.load_dd()

X['T'] = data['duration']
X['E'] = data['observed']

aaf.fit(X, 'T', event_col='E')

After fitting, the instance exposes a cumulative_hazards_ DataFrame containing the estimates of $$\int_0^t b_i(s) \; ds$$:

figsize(12.5,8)

un_continent_name[Africa] un_continent_name[Americas] un_continent_name[Asia] un_continent_name[Europe] un_continent_name[Oceania] regime[T.Military Dict] regime[T.Mixed Dem] regime[T.Monarchy] regime[T.Parliamentary Dem] regime[T.Presidential Dem] start_year baseline
-0.051595 -0.082406 0.010666 0.154493 -0.060438 0.075333 0.086274 -0.133938 0.048077 0.127171 0.000116 -0.029280
-0.014713 -0.039471 0.095668 0.194251 -0.092696 0.115033 0.358702 -0.226233 0.168783 0.121862 0.000053 0.143039
0.007389 -0.064758 0.115121 0.170549 0.069371 0.161490 0.677347 -0.271183 0.328483 0.146234 0.000004 0.297672
-0.058418 0.011399 0.091784 0.205824 0.125722 0.220028 0.932674 -0.294900 0.365604 0.422617 0.000002 0.376311
-0.099282 0.106641 0.112083 0.150708 0.091900 0.241575 1.123860 -0.391103 0.536185 0.743913 0.000057 0.362049

5 rows × 12 columns

AalenAdditiveFitter also has built in plotting:

aaf.plot(columns=['regime[T.Presidential Dem]', 'baseline', 'un_continent_name[Europe]'], iloc=slice(1,15))

Regression is most interesting if we use it on data we have not yet seen, i.e. prediction! We can use what we have learned to predict individual hazard rates, survival functions, and median survival time. The dataset we are using is aviable up until 2008, so let’s use this data to predict the (already partly seen) possible duration of Canadian Prime Minister Stephen Harper.

ix = (data['ctryname'] == 'Canada') * (data['start_year'] == 2006)
harper = X.loc[ix]
print("Harper's unique data point", harper)

Harper's unique data point

array([[    0.,     0.,     1.,     0.,     0.,     0.,     0.,     1.,
0.,     0.,  2003.]])

ax = plt.subplot(2,1,1)

aaf.predict_cumulative_hazard(harper).plot(ax=ax)
ax = plt.subplot(2,1,2)

aaf.predict_survival_function(harper).plot(ax=ax);

Warning

Because of the nature of the model, estimated survival functions of individuals can increase. This is an expected artifact of Aalen’s additive model.

## Cox’s Proportional Hazard model¶

Lifelines has an implementation of the Cox propotional hazards regression model (implemented in R under coxph). The idea behind the model is that the log-hazard of an individual is a linear function of their static covariates and a population-level baseline hazard that changes over time. Mathematically:

$\lambda(t | X) = b_0(t) \exp{\left(\sum_{i=1}^d b_i x_i\right)}$

Note a few facts about this model: the only time component is in the baseline hazard, $$b_0(t)$$. In the above product, the second term is only a scalar factor that only increases or decreases the baseline hazard. Thus a change in a covariate will only increase or decrease this baseline hazard.

### Lifelines implementation¶

The implementation of the Cox model in lifelines, called CoxPHFitter has a similar API to AalensAdditiveFitter. Like R, it has a print_summary function that prints a tabular view of coefficients and related stats.

This example data is from the paper here, avaible as load_rossi in lifelines.

from lifelines.datasets import load_rossi
from lifelines import CoxPHFitter

cph = CoxPHFitter()
cph.fit(rossi_dataset, duration_col='week', event_col='arrest')

cph.print_summary()  # access the results using cph.summary

"""
n=432, number of events=114

coef  exp(coef)  se(coef)       z      p  lower 0.95  upper 0.95
fin  -0.3790     0.6845    0.1914 -1.9806 0.0476     -0.7542     -0.0039   *
age  -0.0572     0.9444    0.0220 -2.6042 0.0092     -0.1003     -0.0142  **
race  0.3141     1.3691    0.3080  1.0198 0.3078     -0.2897      0.9180
wexp -0.1511     0.8597    0.2121 -0.7124 0.4762     -0.5670      0.2647
mar  -0.4328     0.6487    0.3818 -1.1335 0.2570     -1.1813      0.3157
paro -0.0850     0.9185    0.1957 -0.4341 0.6642     -0.4687      0.2988
prio  0.0911     1.0954    0.0286  3.1824 0.0015      0.0350      0.1472  **
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Concordance = 0.640
"""

To access the coefficients and the baseline hazard directly, you can use cph.hazards_ and cph.baseline_hazard_ respectively.

### Convergence¶

Fitting the Cox model to the data involves using gradient descent. Lifelines takes extra effort to help with convergence. If you wish to see the fitting, there is a show_progress parameter in CoxPHFitter.fit function. For further help, see Problems with convergence in the Cox Proportional Hazard Model.

After fitting, the value of the maximum log-likelihood this available using cph._log_likelihood. Similarly, the score and Hessian matrix are available under _score_ and _hessian_ respectively. The _hessian_ can be used the find the covariance matrix of the coefficients.

### Goodness of fit and prediction¶

After fitting, you may want to know how “good” of a fit your model was to the data. Aside from traditional approaches, two methods the author has found useful is to 1. look at the concordance-index (see below section on Model Selection in Survival Regression), available as cph.score_ or in the print_summary and 2. compare spread between the baseline survival function vs the Kaplan Meier survival function (Why? a small spread between these two curves means that the impact of the exponential in the Cox model does very little, whereas a large spread means most of the changes in individual hazard can be attributed to the exponential term). For example, the first figure below is a good fit, and the second figure is a much weaker fit.

After fitting, you can use use the suite of prediction methods (similar to Aalen’s additve model above): .predict_partial_hazard, .predict_survival_function, etc.

cph.predict_partial_hazard(rossi_dataset.drop(["week", "arrest"], axis=1))

### Plotting the coefficients¶

With a fitted model, an altervative way to view the coefficients and their ranges is to use the plot method.

from lifelines.datasets import load_rossi
from lifelines import CoxPHFitter

cph = CoxPHFitter()
cph.fit(rossi_dataset, duration_col='week', event_col='arrest')

cph.plot()

### Checking the proportional hazards assumption¶

A quick and visual way to check the proportional hazards assumption of a variable is to plot the survival curves segmented by the values of the variable. If the survival curves are the same “shape”, and differ only by constant factor, then the assumption holds. A more clear way to see this is to plot what’s called the loglogs curve: the log(-log(survival curve)) vs log(time). If the curves are parallel (and hence do not cross each other), then it’s likely the variable satisfies the assumption. If the curves do cross, likely you’ll have to “stratify” the variable (see next section). In lifelines, the KaplanMeierFitter object has a .plot_loglogs function for this purpose.

The following is the loglogs curves of two variables in our regime dataset. The first is the democracy type, which does have (close to) parallel lines, hence satisfies our assumption:

from lifelines.datasets import load_dd
from lifelines import KaplanMeierFitter

democracy_0 = data.loc[data['democracy'] == 'Non-democracy']
democracy_1 = data.loc[data['democracy'] == 'Democracy']

kmf0 = KaplanMeierFitter()
kmf0.fit(democracy_0['duration'], event_observed=democracy_0['observed'])

kmf1 = KaplanMeierFitter()
kmf1.fit(democracy_1['duration'], event_observed=democracy_1['observed'])

fig, axes = plt.subplots()
kmf0.plot_loglogs(ax=axes)
kmf1.plot_loglogs(ax=axes)

axes.legend(['Non-democracy', 'Democracy'])

plt.show()

The second variable is the regime type, and this variable does not follow the proportional hazards assumption.

### Stratification¶

Sometimes a covariate may not obey the proportional hazard assumption. In this case, we can allow a factor to be adjusted for without estimating its effect. To specify categorical variables to be used in stratification, we specify them in the call to fit:

cph.fit(rossi_dataset, 'week', event_col='arrest', strata=['race'])

cph.print_summary()  # access the results using cph.summary

"""
n=432, number of events=114

coef  exp(coef)  se(coef)       z      p  lower 0.95  upper 0.95
fin  -0.3775     0.6856    0.1913 -1.9731 0.0485     -0.7525     -0.0024   *
age  -0.0573     0.9443    0.0220 -2.6081 0.0091     -0.1004     -0.0142  **
wexp -0.1435     0.8664    0.2127 -0.6746 0.4999     -0.5603      0.2734
mar  -0.4419     0.6428    0.3820 -1.1570 0.2473     -1.1907      0.3068
paro -0.0839     0.9196    0.1958 -0.4283 0.6684     -0.4677      0.3000
prio  0.0919     1.0962    0.0287  3.1985 0.0014      0.0356      0.1482  **
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Concordance = 0.638
"""

## Cox’s Time Varying Proportional Hazard model¶

Warning

This implementation is still experimental.

Often an individual will have a covariate change over time. An example of this is hospital patients who enter the study and, at some future time, may recieve a heart transplant. We would like to know the effect of the transplant, but we cannot condition on whether they recieved the transplant naively. Consider that if patients needed to wait at least 1 year before getting a transplant, then everyone who dies before that year is considered as a non-transplant patient, and hence this would overestimate the hazard of not recieving a transplant.

We can incorporate changes over time into our survival analysis by using a modification of the Cox model above. The general mathematical description is:

$\lambda(t | X) = b_0(t) \exp{\left(\sum_{i=1}^d b_i x_i(t)\right)}$

Note the time-varying $$x_i(t)$$ to denote that covariates can change over time. This model is implemented in lifelines as CoxTimeVaryingFitter. The dataset schema required is different than previous models, so we will spend some time describing this.

### Dataset for time-varying regression¶

Lifelines requires that the dataset be in what is called the long format. This looks like one row per state change, including an ID, the left (exclusive) time point, and right (inclusive) time point. For example, the following dataset tracks three unique subjects.

id start stop group z event
1 0 8 1 0 False
2 0 5 0 0 False
2 5 8 0 1 True
3 0 3 1 0 False
3 3 12 1 1 True

5 rows × 6 columns

In the above dataset, start and stop denote the boundaries, id is the unique identifier per subject, and event denotes if the subject died at the end of that period. For example, subject ID 2 had variable z=0 up to and including the end of time period 5 (we can think that measurements happen at end of the time period.), after which it was set to 1.

So if this is the desired dataset, it can be built up first from smaller datasets. To do this we can use some helper functions provided in lifelines.

Typically, data will be in a format that looks like it comes out of a relational database. You may have a “base” table with ids, durations, and a censorsed flag, and possibly static covariates. Ex:

id duration event var1
1 10 True 0.1
2 12 False 0.5

2 rows × 4 columns

You’ll also have secondary dataset that reference taking future measurements. Example:

id time var2
1 0 1.4
1 4 1.2
1 8 1.5
2 0 1.6

4 rows × 3 columns

where time is the duration from the entry event. Here we see subject 1 had a change in their var2 covariate at the end of time 4 and at the end of time 8. We can use to_long_format to transform the base dataset into a long format and add_covariate_to_timeline to fold the covariate dataset into the original dataset.

from lifelines.utils import to_long_format

base_df = to_long_format(base_df, duration_col="T")
df = add_covariate_to_timeline(base_df, cv, duration_col="time", id_col="id", event_col="event")

id start stop var1 var2 event
1 0 4 0.1 1.4 False
1 4 8 0.1 1.2 False
1 8 10 0.1 1.5 True
2 0 12 0.5 1.6 False

4 rows × 6 columns

From the above output, we can see that subject 1 changed state twice over the observation period, finally expiring at the end of time 10. Subject 2 was a censored case, and we lost them after time 2.

You may have multiple covariates you wish to add, so the above could be streamlined like so:
from lifelines.utils import to_long_format

base_df = to_long_format(base_df, duration_col="T")
df = base_df.pipe(add_covariate_to_timeline, cv1, duration_col="time", id_col="id", event_col="event")\

One additional flag on add_covariate_to_timeline that is of interest is the cumulative_sum flag. By default it is False, but turning it to True will perform a cumulative sum on the covariate before joining. This is useful if the covariates describe an incremental change, instead of a state update. For example, we may have measurements of drugs administered to a patient, and we want to the covariate to reflect how much we have administered since the start. In contrast, a covariate the measure the temperature of the patient is a state update. See Example cumulative total using add_covariate_to_timeline to see an example of this.

For an example of pulling datasets like this from a SQL-store, see Example SQL queries and transformations to get time varying data.

### Fitting the model and a short note on prediction¶

Once your dataset is in the correct orientation, we can use CoxTimeVaryingFitter to fit the model to your data.

from lifelines import CoxTimeVaryingFitter

ctv = CoxTimeVaryingFitter()
ctv.fit(df, id_col="id", event_col="event", start_col="start", stop_col="stop")
ctv.print_summary()
ctv.plot()

Unlike the other regression models, prediction in a time-varying setting is not possible normally. To predict, we would need to know the covariates values beyond the current time, but if we knew that, we would also know if the subject was still alive or not. For this reason, there are no prediction methods attached to CoxTimeVaryingFitter.

## Model Selection in Survival Regression¶

If censorship is present, it’s not appropriate to use a loss function like mean-squared-error or mean-absolute-loss. Instead, one measure is the concordance-index, also known as the c-index. This measure evaluates the accuracy of the ordering of predicted time. It is infact a generalization of AUC, another common loss function, and is interpreted similarly:

• 0.5 is the expected result from random predictions,
• 1.0 is perfect concordance and,
• 0.0 is perfect anti-concordance (multiply predictions with -1 to get 1.0)

The measure is implemented in lifelines under lifelines.utils.concordance_index and accepts the actual times (along with any censorships) and the predicted times.

### Cross Validation¶

Lifelines has an implementation of k-fold cross validation under lifelines.utils.k_fold_cross_validation. This function accepts an instance of a regression fitter (either CoxPHFitter of AalenAdditiveFitter), a dataset, plus k (the number of folds to perform, default 5). On each fold, it splits the data into a training set and a testing set, fits itself on the training set, and evaluates itself on the testing set (using the concordance measure).

from lifelines import CoxPHFitter


text:
help-gnu-emacs
[Top][All Lists]

## Re: What is the best html to latex program on the market or the internet

 From: Edd Barrett Subject: Re: What is the best html to latex program on the market or the internet ? Date: Tue, 23 Oct 2007 08:33:32 -0000 User-agent: G2/1.0

On Oct 23, 2:26 am, address@hidden wrote:
> maybe I should post in european tex groups also
>
> On Oct 22, 2:57 pm, address@hidden wrote:
>
> > Basically, it should do all that any of the tools below and in
>
> > 1/
> > human readable output that maintains the text lines of the source, ie
> > does not scramble the text lines or insert newlines unnecessarily or
> > removes them. inserts minimal latex elements.
>
> > 2/
> > maintains cross-links, ie convert <href to \ref and <name= to \label
>
> > but if the set of htmls is incomplete proceed with the assumption that
> > the reference is there, ie dont delete the links or try to modify them
> > or their addresses. One of the tool I tested is too smart in this
> > respect and actually ruins the result.
>
> > 3/
> > proper conversion of images, tables, etc. No math mode involved in
> > html.
>
> > 4/
> > Even an emacs lisp function could be written by a guru that can do the
> > job.
>
> > 5/
> > Is there any commercial wysiwig tool ?
>
> > LaTeX etc
>
> >     * html2latex is a program based on the NCSA html parser. Contact:
> >     * Another html2latex can combine several HTML files into a single
> > LaTeX file, converting links between the files to references. External
> > URL's can be converted into footnotes or into a bibliography sorted on
> > URL. Contact: address@hidden (Frans J. Faase)
> >     * Another html2latex implemented on Linux by yacc+lex+C. Also
> > available from the TSX-11 Linux FTP site as nc-html2latex-0.97.tar.gz.
> > Contact: address@hidden (Naoya Tozuka)
> >     * htmlatex.pl is a perl script to do the conversion (may be moving
> > soon). Contact: address@hidden (Jake Kesinger)
> >     * There is also a sed script to convert HTML into LaTeX.

Hi,

I don't know if this can be of help:
http://openwetware.org/wiki/User:Austin_J._Che/Extensions/LatexDoc

This is something that we are looking into to allow researchers to
distribute documents in both PDF and web-based (we hope).

Thanks

Edd


text:
# Animating a sprite character with Multiple Parts

I'm trying to animate a 2D character with interchangable parts. Right now, I have each part nested in a general part that is in turn nested in an overall parent like so; Player->Heads->Head1. I have a Controller for each part made and I feel like I should be able to pass the parameters from the Player's animator all the way to Head1's animator as they have the same parameters. I'm not quite sure how to tackle this. Using C#

My own personal way of handling this would be having the Player contain each directly connected part of the body, and so when the player is called to update, you then update each part of the body within that.

A quick example, lets assume that your objects will handle their own rendering.

RenderPlayer()
{
//Player Render code here
this.Arm.RenderArm(PlayerX,PlayerY);
}

With this each Object only needs to know its location compared to the player, and add that to the location information the player passes on. You can also continue to nest this even farther down.

RenderArm(X,Y)
{
//Arm Render code here
this.Hand.RenderHand(ArmX + X, ArmY + Y);
}

The player does not need to know the arm has a hand, so you could add even more, like if the hand has a weapon or the like. You have to factor in offsets of course, but hopefully this will help your creation of something "Rayman like"

It also means that if you swap one head for another, it doesn't need anything special to work, since it fills the same mold.