Ascher Color White


1. Ascher Color White

White cords seem to hold a special place in the pantheon of khipu cord colors. A disproportionate amount of cords are white, they frequently start a cord group, etc. A separate study of White cords is most definitely in order.

I think of White cords as having a special functional marker of some type. In this, their appears some level of agreement. As an example, Jon Clindaniel noted in his Harvard Ph.D. Thesis that white and brown cords might have arithmetic meaning as in White being the sum of brown plus another cord.

Let’s explore possible white cord function markers for a clue to their meaning.

2. Exploratory Data Analysis

2.1 Group Cord Color Sequences

Each cord group has a set of cords each with a color. Express this as a list of colors A, B, C etc. for each cord/color in the group. Let’s see what are the most common group cord sequences

Code
# Load Khipus
(khipu_dict, all_khipus) = kamayuq.fetch_khipus()
plotly.offline.init_notebook_mode(connected = False);

# Ascher-Group Color Frequency returns a "markov" chain of colors for all group's sorted by frequency...
from ascher_group_color_frequency import count_most_common_group_colors
(color_rep_sorted_frequency, color_rep_sorted_markov) = count_most_common_group_colors()

color_rep_frequency_width = [(color_string, count, len(color_string.split(" "))) for (color_string, count) in color_rep_sorted_frequency]
df = pd.DataFrame(color_rep_frequency_width, columns = ['color_string', 'count', 'num_colors'])
df.head(20)
color_string count num_colors
0 W 628 1
1 PK 368 1
2 AB 312 1
3 LK 291 1
4 W W W W W W 149 6
5 W W W W W W W 137 7
6 DB 125 1
7 W W W 106 3
8 MB 106 1
9 YB 97 1
10 W W 82 2
11 W B W 70 3
12 W:AB 58 1
13 AB AB AB 53 3
14 LB LB LB LB LB 52 5
15 W W W W 51 4
16 AB AB AB AB 44 4
17 W W W W W 41 5
18 W W W W W W W W 40 8
19 W AB 40 2
<Figure size 6000x3000 with 0 Axes>

You can see that White cord groups occur A LOT.

5 of the top 6 cord color sequences, are White Cords.

2.2 Initial Group Cord Color Sequences

When white cords are not in bands, they seem to occur at the beginning and end of groups (a title cord? an info cord?). Let’s explore their distribution to see if that statement holds true.

Let’s graph their frequency of occurence by position/cord group length.

A preview:

with a full view here: White Cord Frequencies in Cord Groups

The conclusion: From the above graphic, you can observe that White cords have a SMALL tendency to lie on the left or right of a cord group for small group lengths. There is a small amount of evidence that white cords are a group “title” or info block. While underwhelming, it is especially evident in those magic Inka ayllu numbers for groups of 6, 7 (1 white cord + 6 ayllu cords), 9 and 10 cords.

2.3 White Cord Values

Where do white cord’s mean cord values arise versus other cord color mean values?

Code
from statistics import mean

all_pendant_cords = []
for aKhipu in all_khipus: all_pendant_cords += aKhipu[:,:]
zero_value_pendant_cords = [aCord for aCord in all_pendant_cords if aCord.knotted_value()==0 ]
non_zero_pendant_cords = [aCord for aCord in all_pendant_cords if aCord.knotted_value() > 0]

def add_cord(dict, cord_color, cord_value):
    if cord_color in dict.keys(): dict[cord_color].append(cord_value)
    else: dict[cord_color] = [cord_value]

def num_color_occurrences(cord_dict):
    color_value = {}
    for cord_color, value_list in cord_dict.items():
        color_value[cord_color] = math.log(len(value_list),10)
    return color_value

def mean_color_value(cord_dict):
    color_value = []
    for cord_color, value_list in cord_dict.items():
        color_value.append((cord_color, mean(value_list)))
    return color_value

def cord_statistic(cord_dict):
    color_value = []
    for cord_color, value_list in cord_dict.items():
        color_value.append((cord_color, [min(value_list), max(value_list), mean(value_list), math.stdev(value_list)]))
    return color_value

cord_sums = {}
for aCord in non_zero_pendant_cords:
    add_cord(cord_sums, aCord.longest_ascher_color(), aCord.knotted_value())

colors_by_value = sorted(mean_color_value(cord_sums), key=lambda x : x[1], reverse=True)
colors_by_occurrence = num_color_occurrences(cord_sums)
top_colors_by_value = colors_by_value[:75]
top_color_occurrences = [colors_by_occurrence[aColor] for (aColor, count) in top_colors_by_value]

First let’s evaluate the cord value range/distribution for white cords.

Code
def cord_statistic(cord_dict):
    color_value = []
    for cord_color, value_list in cord_dict.items():
        std_dev = statistics.stdev(value_list) if len(value_list)>1 else 0
        color_value.append((cord_color, [min(value_list), max(value_list), mean(value_list), std_dev]))
    return color_value
stats = cord_statistic(cord_sums)
white_range = [(x,y) for (x,y) in stats if x=='W'][0]
print(f"Range for white cords values [min, max, mean, std_dev] is {white_range}")
color_sum_white_df = pd.DataFrame(cord_sums['W'],columns = ['cord_value'])
fig = px.histogram(color_sum_white_df, x="cord_value", log_y=True,
                  title="Histogram of White Cord Values - Count is Log_10",
                  labels={"count":"Log_10 of Count"})
fig.update_layout(width=944).show()
Range for white cords values [min, max, mean, std_dev] is ('W', [1, 320535, 439.6537875640493, 4535.173677379783])

White cords range from a low of 0/1 to 320,535, a mean of 440, and a very large standard deviation of 4,541.

Next, let’s examine white mean cord values compared to other colors.

Code
color_df_data = list(zip([aColor for (aColor, count) in top_colors_by_value], top_color_occurrences, [count for (aColor, count) in top_colors_by_value]))
color_by_value_df = pd.DataFrame(color_df_data, columns = ['color', 'log_num_occurrences', 'mean_value']).sort_values(by=['log_num_occurrences'], ascending=False)
color_by_value_df.head(50)
color log_num_occurrences mean_value
37 W 3.858597 439.653788
41 AB 3.617315 384.398503
49 B 3.107888 330.223869
54 W:MB 2.872156 317.491275
47 LB 2.665581 344.870410
32 NB 2.647383 468.324324
22 GG 2.439333 632.632727
42 YG 2.217484 379.072727
74 BG 2.195900 223.910828
21 W:GG 2.167317 689.523810
36 W-MB 2.086360 450.549180
44 W-AB 1.913814 358.548780
64 LG 1.875061 287.453333
43 W%MB 1.875061 377.506667
62 W-KB 1.857332 295.666667
19 W%AB 1.845098 813.685714
56 W-DB 1.770852 311.898305
71 W:NB 1.740363 235.381818
52 AB-MB 1.707570 320.862745
72 RM 1.707570 234.470588
50 GL 1.662758 329.782609
17 B:CB 1.477121 954.233333
66 AB-GG 1.447158 260.535714
28 W:BD 1.431364 525.111111
4 B:YG 1.431364 2980.148148
45 B:BB 1.397940 357.040000
5 BL:AB 1.380211 2419.083333
10 B:GG 1.361728 1598.000000
53 AB:GG:MB 1.255273 320.055556
70 EB 1.255273 242.777778
11 W-BS 1.204120 1421.375000
68 B:LB 1.204120 246.187500
18 BL 1.204120 833.875000
69 W-GG 1.146128 245.000000
23 B:GG:LB 1.113943 632.307692
60 W:GG:MB 1.113943 297.923077
57 B:G 1.079181 310.583333
34 RM-MB 1.041393 455.727273
67 RD 1.000000 259.000000
2 YG:BB 0.954243 4251.000000
15 AB:NB 0.903090 1203.500000
30 B-YG 0.903090 488.000000
25 W:AB:GG 0.903090 612.500000
33 YB:BL 0.778151 464.666667
13 0R 0.778151 1284.000000
20 AB%MB 0.698970 762.600000
6 B-GG 0.698970 2246.400000
65 B-BB 0.698970 287.200000
26 W%GG 0.602060 592.500000
51 GG-KB 0.477121 325.333333
Code
color_by_value_df = color_by_value_df.sort_values(by=['log_num_occurrences'], ascending=False)
color_by_value_df.head(50)
size_vec = [x for x in list(color_by_value_df.log_num_occurrences.values)]
fig = (px.scatter(color_by_value_df, x='color', y='mean_value', log_y=True,
             size=size_vec, 
             color='log_num_occurrences', 
             hover_name='color', hover_data=['mean_value', 'log_num_occurrences'], 
             labels={"color": "Ascher Color", "mean_value": "Mean Cord Value", "log_num_occurrences":"Log_10 Occurrences"},
             title="Top 75 Mean Cord Values by Color, Sorted by # Occurences", width=944, height=1944)
         .update_layout(showlegend=True,
                        xaxis = dict(tickfont = dict(size=8)))
         .show())
color log_num_occurrences mean_value
37 W 3.858597 439.653788
41 AB 3.617315 384.398503
49 B 3.107888 330.223869
54 W:MB 2.872156 317.491275
47 LB 2.665581 344.870410
32 NB 2.647383 468.324324
22 GG 2.439333 632.632727
42 YG 2.217484 379.072727
74 BG 2.195900 223.910828
21 W:GG 2.167317 689.523810
36 W-MB 2.086360 450.549180
44 W-AB 1.913814 358.548780
64 LG 1.875061 287.453333
43 W%MB 1.875061 377.506667
62 W-KB 1.857332 295.666667
19 W%AB 1.845098 813.685714
56 W-DB 1.770852 311.898305
71 W:NB 1.740363 235.381818
72 RM 1.707570 234.470588
52 AB-MB 1.707570 320.862745
50 GL 1.662758 329.782609
17 B:CB 1.477121 954.233333
66 AB-GG 1.447158 260.535714
28 W:BD 1.431364 525.111111
4 B:YG 1.431364 2980.148148
45 B:BB 1.397940 357.040000
5 BL:AB 1.380211 2419.083333
10 B:GG 1.361728 1598.000000
70 EB 1.255273 242.777778
53 AB:GG:MB 1.255273 320.055556
11 W-BS 1.204120 1421.375000
68 B:LB 1.204120 246.187500
18 BL 1.204120 833.875000
69 W-GG 1.146128 245.000000
23 B:GG:LB 1.113943 632.307692
60 W:GG:MB 1.113943 297.923077
57 B:G 1.079181 310.583333
34 RM-MB 1.041393 455.727273
67 RD 1.000000 259.000000
2 YG:BB 0.954243 4251.000000
15 AB:NB 0.903090 1203.500000
30 B-YG 0.903090 488.000000
25 W:AB:GG 0.903090 612.500000
33 YB:BL 0.778151 464.666667
13 0R 0.778151 1284.000000
20 AB%MB 0.698970 762.600000
6 B-GG 0.698970 2246.400000
65 B-BB 0.698970 287.200000
26 W%GG 0.602060 592.500000
9 W:YB:BL 0.477121 1727.000000

Fascinating! Note how color-combinations take up the majority of the high values. Also note the position White plays - 37’th on the list.

Let’s look at the graph sorted by mean cord value:

Code
color_by_value_df = color_by_value_df.sort_values(by=['mean_value'], ascending=False)
size_vec = [x for x in list(color_by_value_df.log_num_occurrences.values)]
fig = (px.scatter(color_by_value_df, x='color', y='mean_value', log_y=True,
             size=size_vec, 
             color='log_num_occurrences', 
             hover_name='color', hover_data=['mean_value', 'log_num_occurrences'], 
             labels={"color": "Ascher Color", "mean_value": "Mean Cord Value (Log_10)", "log_num_occurrences":"Log_10 Occurrences"},
             title="Top 75 Mean Cord Values by Color, Sorted by Mean Cord Value", width=944, height=1944)
         .update_layout(showlegend=True,
                        xaxis = dict(tickfont = dict(size=8)))
         .show())

2.4 White Cord Values for Pendant Pendant Sums

We are finally in a position to evaluate Jon Clindaniel’s proposal that White cords are grammatical markers for sums. Let’s use the pendant-pendant-sums fieldmark (the most common sum relationship) as a proxy for this examination. First, let’s load the data and draw a similar graph to the one above - but this time we will evaluate how often the color occurs, rather than it’s mean value.

Code
from fieldmark_ascher_pendant_pendant_sum import Fieldmark_Pendant_Pendant_Sum
aFieldmark = Fieldmark_Pendant_Pendant_Sum()
khipu_df = aFieldmark.dataframes[0].dataframe
sum_cord_df = aFieldmark.dataframes[1].dataframe

def pendant_mean_by_color(aColor):
    cords_with_color_df = sum_cord_df[sum_cord_df.cord_color==aColor]
    pendant_color_values = list(cords_with_color_df.cord_value.values)
    the_mean_value = mean(pendant_color_values) if len(pendant_color_values) > 0 else 0
    return math.log(the_mean_value,10) if the_mean_value > 0 else 0

def pendant_color_occurrences(aColor):
    cords_with_color_df = sum_cord_df[sum_cord_df.cord_color==aColor]
    num_occurrences = len(cords_with_color_df)
    return num_occurrences

all_colors = set(sum_cord_df.cord_color.values)
color_frequency = [(aColor, pendant_color_occurrences(aColor), pendant_mean_by_color(aColor)) for aColor in all_colors]
color_frequency_df = pd.DataFrame(color_frequency, columns = ['color', 'num_occurrences', 'log_mean_value'])
color_frequency_df = color_frequency_df.sort_values(by=['num_occurrences'], ascending=False);
color_frequency_df = color_frequency_df[:75]

legend_text = "<i style=\"font-size:10pt;\">&nbsp;&nbsp;Size/Color = Mean(Cord Values)" + \
              " - Hover Over Circles to View Khipu/Cord Info</i>"
size_vec = [math.log10(x) for x in list(color_frequency_df.log_mean_value.values)]
fig = px.scatter(color_frequency_df, x='color', y='num_occurrences', log_y=True,
             size=size_vec, 
             color='num_occurrences', 
             hover_name='color', hover_data=['log_mean_value', 'num_occurrences'], 
             labels={"color": "Ascher Color",'num_occurrences':"Color Frequency", "log_mean_value": "Log_10 of Mean Cord Value", },
             title=f"Pendant Sum Cords by Color Frequency (Top 75){legend_text}", width=944, height=944).update_layout(showlegend=True).show()

Here you can see that White predominates sum relationships. SUBSTANTIALLY. This lends credence to Dr. Clindaniel’s argument. But WAIT!…

Let’s do one more thing. Let’s compare this distribution to an overall distribution of pendant cords in general.

Code
from collections import OrderedDict, Counter

def build_pendant_color_frequencies():
    ascher_colors = []
    for aKhipu in all_khipus:
        khipu_cords = aKhipu.pendant_cords()
        for cord_index, aCord in enumerate(khipu_cords):
            cord_colors = [aColor.full_color for aColor in aCord.ascher_cord_colors]
            if len(cord_colors)>0: ascher_colors += cord_colors
    
    return OrderedDict(Counter(ascher_colors).most_common()) 

pendant_color_frequency_dict = build_pendant_color_frequencies()
pendant_sum_color_frequency_dict = OrderedDict(zip(color_frequency_df.color.values, color_frequency_df.num_occurrences.values))
theta = ku.degrees_between_dicts(pendant_color_frequency_dict, pendant_sum_color_frequency_dict)
print(f"Angle between all_colors vector and pendant pendant sum color vector is {theta:0.2f}° degrees")
Angle between all_colors vector and pendant pendant sum color vector is 4.35° degrees

That’s astounding. Pendant sum color frequency matches almost exactly (within 5° degrees) to overall pendant color frequency amongst all the khipus.

If we are to look at the predominance of white sums in the above scatterplot Top 75 Pendant Sum Cords by Color Frequency one can conclude that Dr. Clindaniel’s argument makes sense. However, the closeness of the vector angle disproves the case. If color was a grammatical marker, we would expect to see a more significant difference. Consequently, the apparent conclusion is that color does not play a grammatical role in summation patterns.

So far, two types of Ascher Sum Relationships have been politely ignored:

  • Colored Pendant Cord Sums (by Color) - Pendant cords that are Sums of a set of Contiguous Pendant cords, with the Same Color, ignoring parent cord group boundaries and
  • Indexed Pendant Sum Cords - Pendant cords that are Sums of Similarly Indexed cords in Contiguous Groups to the right or left of the cord.

In these type of cross-linked sums (as opposed to the contiguous sums of pendant-pendant sums), the grammatical marker is position, not color. As an example, look at the large cord value khipu UR1143 where the sums are indicated by position index and also by similar color.

Dr. Clindaniels argument would apply then, only to pendant pendant sums, and that conclusion now seems unlikely.

The reverse argument could also be made. The majority of pendants are sum cords. Is that true? Let’s look at just this fieldmark alone - pendant pendant sums, which has the most number of sum cords:

Code
num_khipu_pendants = sum([khipu_dict[khipu_name].num_pendant_cords() for khipu_name in sum_cord_df.name.values])
num_sum_pendants = len(aFieldmark.dataframes[1].dataframe)
print(f"num pendant sum_cords is {num_sum_pendants}, out of a set of {num_khipu_pendants} total sum khipus pendants")
percentage = (100.0*num_sum_pendants/float(num_khipu_pendants))
print(f"That's a ratio of {percentage:.2f}%")
num pendant sum_cords is 8097, out of a set of 1769959 total sum khipus pendants
That's a ratio of 0.46%

So 0.5% - less than 1/2 of 1% - of the cords in khipus having a pendant pendant sum cord relations ship have pendants that are sum cords. So that argument might have trouble bearing weight…

As a final confirmation - let’s look at the color distributions of the two sets of colors (pendant sum colors) vs (pendant colors). Click on each image to view it full-size.

Click on image to view larger


Click on image to view larger

3. Conclusions

While white cords comprise a third of all pendant cords, and of cord groups of white, we don’t yet know what their color significance is. One theory, that they are grammatical markers for addition, appears disproved. However, they do show interesting levels of positional significance, appearing at the end or beginning of cord groups that contain many sums (sum groups), and in certain spikes in larger groups (i.e. in odd positions more than even ones).