Q:

Creating a feature dictionary for Python machine learning (naive bayes) algorithm

I would like predict, for example, Chinese vs. non-Chinese ethnicities using last names. Particularly I want to extract three-letter substrings from the last names. So for example, the last name "gao" will give one feature as "gao" while "chan" will give two features as "cha" and "han".
The splitting is successfully done in the three_split function below. But as far as I understand, to incorporate this as a feature set I need to return the output as dictionary. Any hints of how to do that? For the dictionary of "Chan", the dictionary should return "cha" and "han" as TRUE.
from nltk.classify import PositiveNaiveBayesClassifier
import re

chinese_names = ['gao', 'chan', 'chen', 'Tsai', 'liu', 'Lee']

nonchinese_names = ['silva', 'anderson', 'kidd', 'bryant', 'Jones', 'harris', 'davis']

def three_split(word):
    word = word.lower()
    word = word.replace(" ", "_")
    split = 3
    return [word[start:start+split] for start in range(0, len(word)-2)]

positive_featuresets = list(map(three_split, chinese_names))
unlabeled_featuresets = list(map(three_split, nonchinese_names))
classifier = PositiveNaiveBayesClassifier.train(positive_featuresets, 
    unlabeled_featuresets)

print three_split("Jim Silva")
print classifier.classify(three_split("Jim Silva"))

A:

Here's a white-box answer:
Using your orginal code, it outputs:
Traceback (most recent call last):
  File "test.py", line 17, in <module>
    unlabeled_featuresets)
  File "/usr/local/lib/python2.7/dist-packages/nltk/classify/positivenaivebayes.py", line 108, in train
    for fname, fval in featureset.items():
AttributeError: 'list' object has no attribute 'items'

Looking at line 17: 
classifier = PositiveNaiveBayesClassifier.train(positive_featuresets, 
    unlabeled_featuresets)

It seems that the PositiveNaiveBayesClassifier requires an object that has an attribute '.items()' and intuitively it should be a dict if the NLTK code is pythonic.
Looking at https://github.com/nltk/nltk/blob/develop/nltk/classify/positivenaivebayes.py#L88, there isn't any clear explanation of what the positive_featuresets parameter should contain:

:param positive_featuresets: A list of featuresets that are known as
  positive examples (i.e., their label is True).

Checking the docstring, we see this example:
Example:
    >>> from nltk.classify import PositiveNaiveBayesClassifier
Some sentences about sports:
    >>> sports_sentences = [ 'The team dominated the game',
    ...                      'They lost the ball',
    ...                      'The game was intense',
    ...                      'The goalkeeper catched the ball',
    ...                      'The other team controlled the ball' ]
Mixed topics, including sports:
    >>> various_sentences = [ 'The President did not comment',
    ...                       'I lost the keys',
    ...                       'The team won the game',
    ...                       'Sara has two kids',
    ...                       'The ball went off the court',
    ...                       'They had the ball for the whole game',
    ...                       'The show is over' ]
The features of a sentence are simply the words it contains:
    >>> def features(sentence):
    ...     words = sentence.lower().split()
    ...     return dict(('contains(%s)' % w, True) for w in words)
We use the sports sentences as positive examples, the mixed ones ad unlabeled examples:
    >>> positive_featuresets = list(map(features, sports_sentences))
    >>> unlabeled_featuresets = list(map(features, various_sentences))
    >>> classifier = PositiveNaiveBayesClassifier.train(positive_featuresets,
    ...                                                 unlabeled_featuresets)

Now we find the feature() function that converts the sentences into features and returns
dict(('contains(%s)' % w, True) for w in words)

Basically this is the thing that has the ability to call .items(). Looking at the dict comprehension it seems like 'contains(%s)' % w is a little redundant unless it's for human readability. So you could have just used dict((w, True) for w in words).
Also, the replacement of space with underscore might also be redundant unless there's use for it later on.
Lastly, the slicing and limited iteration could have been replaces with the ngram function that can extract character ngrams, e.g. 
>>> word = 'alexgao'
>>> split=3
>>> [word[start:start+split] for start in range(0, len(word)-2)]
['ale', 'lex', 'exg', 'xga', 'gao']
# With ngrams
>>> from nltk.util import ngrams
>>> ["".join(ng) for ng in ngrams(word,3)]
['ale', 'lex', 'exg', 'xga', 'gao']

Your feature extraction function could have been simplified as such:
from nltk.util import ngrams
def three_split(word):
    return dict(("".join(ng, True) for ng in ngrams(word.lower(),3))

[out]:
{'im ': True, 'm s': True, 'jim': True, 'ilv': True, ' si': True, 'lva': True, 'sil': True}
False

In fact, NLTK classifiers are so versatile that you can use tuples of characters as features so you don't need to patch the ngram up when extracting the features, i.e.:
from nltk.classify import PositiveNaiveBayesClassifier
import re
from nltk.util import ngrams

chinese_names = ['gao', 'chan', 'chen', 'Tsai', 'liu', 'Lee']

nonchinese_names = ['silva', 'anderson', 'kidd', 'bryant', 'Jones', 'harris', 'davis']

def three_split(word):
    return dict(((ng, True) for ng in ngrams(word.lower(),3))

positive_featuresets = list(map(three_split, chinese_names))
unlabeled_featuresets = list(map(three_split, nonchinese_names))

classifier = PositiveNaiveBayesClassifier.train(positive_featuresets, 
    unlabeled_featuresets)

print three_split("Jim Silva")
print classifier.classify(three_split("Jim Silva"))

[out]:
{('m', ' ', 's'): True, ('j', 'i', 'm'): True, ('s', 'i', 'l'): True, ('i', 'l', 'v'): True, (' ', 's', 'i'): True, ('l', 'v', 'a'): True, ('i', 'm', ' '): True}

