├── .gitignore ├── MANIFEST.in ├── README.rst ├── behavior2vec ├── TODO.txt ├── __init__.py ├── behavior2vec.py ├── data │ ├── .gitignore │ └── item-info-1000.pck ├── gen-sim-log.py └── tests │ └── __init__.py ├── bin ├── b2v-most-similar-behavior.py ├── b2v-most-similar-item.py └── b2v-train.py └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | behavior2vec.egg-info/ 2 | build/ 3 | dist/ 4 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.rst 2 | include behavior2vec/data/* 3 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ====== 2 | behavior2vec 3 | ====== 4 | 5 | This package implements the ``Behavior2Vec`` algorithm introduced in the following paper. 6 | Please cite the paper if you find this package useful. 7 | 8 | Chen, Hung-Hsuan. "Behavior2Vec: Generating Distributed Representations of Users’ Behaviors on Products for Recommender Systems." *ACM Transactions on Knowledge Discovery from Data (TKDD)* 12.4 (2018). 9 | 10 | BibTeX:: 11 | 12 | @article{chen2018behavior2vec, 13 | title={Behavior2Vec: Generating Distributed Representations of Users’ Behaviors on Products for Recommender Systems}, 14 | author={Chen, Hung-Hsuan}, 15 | journal={ACM Transactions on Knowledge Discovery from Data (TKDD)}, 16 | volume={12}, 17 | issue={4}, 18 | year={2018}, 19 | publisher={ACM} 20 | } 21 | 22 | 23 | Paper download: 24 | 25 | * URL1: http://in.ncu.edu.tw/~hhchen/academic_works/chen18-tkdd-b2v.pdf 26 | 27 | * URL2: https://dl.acm.org/citation.cfm?id=3184454 28 | 29 | 30 | **************************** 31 | Sample usage (with caution): 32 | **************************** 33 | 34 | >>> import behavior2vec 35 | >>> model = behavior2vec.Behavior2Vec() 36 | >>> model.train('./data/sample_data.txt') # log file, one line per user (session) 37 | >>> model.most_similar_behavior('v-100', 'p', k=5) # predict most similar p-type (purchasing) behavior to 'v-100' (view item 100) 38 | >>> model.most_similar_item('100', k=5) # predict most similar items to item 100 39 | 40 | *************** 41 | How to install: 42 | *************** 43 | 44 | ``python setup.py install`` 45 | 46 | ******************* 47 | Command line tools: 48 | ******************* 49 | 50 | After installation, you may run the following scripts directly (tested in Ubuntu 16.04 and OS X El Capitan). 51 | 52 | To generate the Behavior2Vec model, run: 53 | ======================================== 54 | 55 | ``b2v-train.py [train-file]`` 56 | 57 | This will generate a model file of the name ``[train-file]-b2v-model.pck`` under the same directory. 58 | 59 | To show the most similar behavior, run: 60 | ======================================= 61 | 62 | ``b2v-most-similar-behavior.py [test-file] [model-file] [output-file] [k] [behavior-type]`` 63 | 64 | The ``[test-file]`` contains a list of query behaviors, one behavior per line. 65 | 66 | The ``[output-file]`` is the output file, which contains a list of the top ``[k]`` most simiar behaviors 67 | 68 | To show the most similar items, run: 69 | ==================================== 70 | 71 | ``b2v-most-similar-item.py [test-file] [model-file] [output-file] [k]`` 72 | 73 | The ``[test-file]`` contains a list of query items, one behavior per line. 74 | The ``[output-file]`` is the output file, which contains a list of the top ``[k]`` most simiar items 75 | -------------------------------------------------------------------------------- /behavior2vec/TODO.txt: -------------------------------------------------------------------------------- 1 | 1. Write unit-tests 2 | -------------------------------------------------------------------------------- /behavior2vec/__init__.py: -------------------------------------------------------------------------------- 1 | from .behavior2vec import Behavior2Vec 2 | -------------------------------------------------------------------------------- /behavior2vec/behavior2vec.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | ''' 5 | This module runs the behavior2vec model 6 | ''' 7 | 8 | import collections 9 | import functools 10 | import itertools 11 | import sys 12 | 13 | import gensim 14 | import numpy as np 15 | 16 | from scipy import spatial 17 | 18 | 19 | class MyLog(object): 20 | def __init__(self, filename): 21 | self.filename = filename 22 | 23 | def __iter__(self): 24 | for line in open(self.filename): 25 | yield line.split() 26 | 27 | 28 | class Behavior2Vec(object): 29 | def __init__(self): 30 | self.behavior_embeddings = None 31 | self.full_model = None 32 | self.behavior_model = {} 33 | self.item_model = None 34 | 35 | def train(self, log_file, size=1, window=5): 36 | logs = MyLog(log_file) 37 | self.full_model = gensim.models.Word2Vec(logs, min_count=1, size=size, window=window) 38 | self.behavior_embeddings = self._gen_behavior_embedding() 39 | self._gen_behavior_model() 40 | self._gen_item_model() 41 | 42 | def _gen_behavior_model(self): 43 | for behavior in self.behavior_embeddings: 44 | self.behavior_model[behavior] = {'label': list(self.behavior_embeddings[behavior].keys()), 45 | 'model': spatial.cKDTree(list(self.behavior_embeddings[behavior].values()))} 46 | 47 | def _gen_item_model(self): 48 | item_embeddings = self._gen_item_embeddings() 49 | self.item_model = {'label': list(item_embeddings.keys()), 50 | 'model': spatial.cKDTree(list(item_embeddings.values()))} 51 | 52 | def _gen_behavior_embedding(self): 53 | behavior_embeddings = collections.defaultdict(lambda: collections.defaultdict()) 54 | for k in self.full_model.wv.vocab.keys(): 55 | behavior, item_id = k.split('-') 56 | behavior_embeddings[behavior][item_id] = self.full_model.wv[k] 57 | 58 | # fill the missing behavior-embeddings by the average embeddings 59 | all_items = set(itertools.chain.from_iterable([list(behavior_embeddings[behavior].keys()) for behavior in behavior_embeddings])) 60 | avg_behavior_embeddings = self._gen_avg_behavior_embeddings(behavior_embeddings) 61 | for item_id in all_items: 62 | for behavior in behavior_embeddings.keys(): 63 | if item_id not in behavior_embeddings[behavior]: 64 | behavior_embeddings[behavior][item_id] = avg_behavior_embeddings[behavior] 65 | return dict(behavior_embeddings) 66 | 67 | def _gen_avg_behavior_embeddings(self, behavior_embeddings): 68 | avg_behavior_embeddings = {} 69 | for behavior in behavior_embeddings: 70 | for item_id in behavior_embeddings[behavior]: 71 | if behavior not in avg_behavior_embeddings: 72 | avg_behavior_embeddings[behavior] = behavior_embeddings[behavior][item_id] 73 | else: 74 | avg_behavior_embeddings[behavior] += behavior_embeddings[behavior][item_id] 75 | for behavior in avg_behavior_embeddings: 76 | avg_behavior_embeddings[behavior] /= len(behavior_embeddings[behavior]) 77 | return avg_behavior_embeddings 78 | 79 | def _gen_item_embeddings(self): 80 | behaviors = list(self.behavior_embeddings.keys()) 81 | n_behaviors = len(behaviors) 82 | vector_size = len(list(list(self.behavior_embeddings.values())[0].values())[0]) 83 | item_embeddings = collections.defaultdict(functools.partial(np.zeros, (vector_size * n_behaviors,))) 84 | for i, behavior in enumerate(self.behavior_embeddings): 85 | for item_id in self.behavior_embeddings[behavior]: 86 | item_embeddings[item_id][i * vector_size : (i+1) * vector_size] = self.behavior_embeddings[behavior][item_id] 87 | return item_embeddings 88 | 89 | def most_similar_behavior(self, cur_behavior, target_behavior_type=None, k=1, disregard_self=True): 90 | cur_behavior_embedding = self.full_model.wv[cur_behavior] 91 | if target_behavior_type is None: 92 | all_dists = [] 93 | all_indices = [] 94 | all_behavior_types = [] 95 | for b in self.behavior_model.keys(): 96 | dists, indices = self.behavior_model[b]['model'].query(cur_behavior_embedding, k+1) 97 | all_dists.extend(dists) 98 | all_indices.extend(indices) 99 | all_behavior_types.extend([b] * len(dists)) 100 | small_indices = np.argpartition(all_dists, k+1) 101 | small_indices = small_indices[1:] if disregard_self else small_indices[:-1] 102 | return [all_behavior_types[i] + '-' + self.behavior_model[all_behavior_types[i]]['label'][all_indices[i]] for i in small_indices], [all_dists[i] for i in small_indices] 103 | 104 | dists, indices = self.behavior_model[target_behavior_type]['model'].query(cur_behavior_embedding, k+1) 105 | if disregard_self: 106 | return [target_behavior_type + '-' + self.behavior_model[target_behavior_type]['label'][i] for i in indices[1:]], dists[1:] 107 | else: 108 | return [target_behavior_type + '-' + self.behavior_model[target_behavior_type]['label'][i] for i in indices[:-1]], dists[:-1] 109 | 110 | def most_similar_item(self, cur_item, k=1, disregard_self=True): 111 | cur_item_embedding = None 112 | for i, behavior_type in enumerate(self.behavior_embeddings.keys()): 113 | if i == 0: 114 | cur_item_embedding = self.behavior_embeddings[behavior_type][cur_item] 115 | else: 116 | cur_item_embedding = np.append(cur_item_embedding, self.behavior_embeddings[behavior_type][cur_item]) 117 | dists, indices = self.item_model['model'].query(cur_item_embedding, k+1) 118 | if disregard_self: 119 | return [self.item_model['label'][i] for i in indices[1:]], dists[1:] 120 | else: 121 | return [self.item_model['label'][i] for i in indices[:-1]], dists[:-1] 122 | 123 | -------------------------------------------------------------------------------- /behavior2vec/data/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !item-info-1000.pck 4 | -------------------------------------------------------------------------------- /behavior2vec/data/item-info-1000.pck: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ncu-dart/behavior2vec/20689603fc98f9f1e97cab4ef765b1deb5ab0d89/behavior2vec/data/item-info-1000.pck -------------------------------------------------------------------------------- /behavior2vec/gen-sim-log.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | ''' 5 | This script generates the simulation data 6 | ''' 7 | 8 | 9 | import numpy as np 10 | import os 11 | import pickle 12 | import sys 13 | 14 | 15 | def normalize_list(li): 16 | return [float(e) / sum(li) for e in li] 17 | 18 | 19 | def gen_items(n_items=100000, filename=''): 20 | ''' 21 | Generation rule: 22 | 1. Generate 100,000 items 23 | 2. For each of the 100,000 items, generate x1 alternative items, x1 ~ max(1, round(N(mu=10, sigma=3))), assign alternative scores s1 to these x1 items, s1~unif(0.5, 1) 24 | 3. For each of the 100,000 items, generate x2 affiliated items, x2 ~ max(1, round(N(mu=5, sigma=2))), assign affiliated scores s2 to these x2 items, s2~unif(0.5, 1) 25 | return: 26 | a dictionary of items of the following format 27 | items = {item-id: [(alter-item-list), (alter-item-prob-list)], [(affil-item-list, affil-item-prob-list), ...]]} 28 | ''' 29 | if os.path.isfile(filename): 30 | with open(filename, 'rb') as f: 31 | items = pickle.load(f) 32 | return items 33 | 34 | 35 | items = {} 36 | for item_id in range(n_items): 37 | print("Generating item (%i / %i)" % (item_id + 1, n_items)) 38 | n_alter_items = max(1, round(np.random.normal(loc=10, scale=3))) 39 | alter_items = np.random.choice(range(n_items), n_alter_items, replace=False).tolist() 40 | alter_scores = normalize_list(np.random.uniform(low=.5, high=1., size=n_alter_items).tolist()) 41 | 42 | n_affil_items = max(1, round(np.random.normal(loc=5, scale=2))) 43 | affil_items = np.random.choice(range(n_items), n_affil_items, replace=False).tolist() 44 | affil_scores = normalize_list(np.random.uniform(low=.5, high=1., size=n_affil_items).tolist()) 45 | items[item_id] = [[alter_items, alter_scores], [affil_items, affil_scores]] 46 | return items 47 | 48 | 49 | def gen_next_item(cur_behavior, cur_item, session, items): 50 | prob = np.random.random() 51 | if prob < .1: 52 | return int(np.random.choice(session).split('-')[1]) 53 | if cur_behavior == 'p': 54 | return np.random.choice(items[cur_item][1][0], p=items[cur_item][1][1]) if prob < .7 else np.random.choice(items[cur_item][0][0], p=items[cur_item][0][1]) 55 | if cur_behavior == 'v': 56 | return np.random.choice(items[cur_item][0][0], p=items[cur_item][0][1]) if prob < .7 else np.random.choice(items[cur_item][1][0], p=items[cur_item][1][1]) 57 | sys.exit(-1) 58 | 59 | 60 | def gen_logs(items, n_sessions=10000, session_avg_len=10): 61 | ''' 62 | Generation rule: 63 | 1. generate 10000 users (sessions) 64 | 2. The session length follows a exponential distribution, min session length = 2 65 | 3. Each user randomly select one item as the inital item 66 | 4. If a user continues to stay on the website, to view or to purchase is based on a uniform distribution 67 | 5. If a user is viewing an item, randomly select the next item with prob. 0.1 and select the next item in alternative-item-list with prob. 0.6, and select the next item in affiliated-item-list with prob. 0.3 68 | 6. If a user is purchasing an item and will view an item, randomly select the next item within the session with prob. .1 and select the next item in affiliated-item-list with prob. 0.6, and select the next item in alternative-item-list with prob. 0.3 69 | ''' 70 | logs = [] 71 | for uid in range(n_sessions): 72 | print("Generating session (%i / %i)" % (uid + 1, n_sessions)) 73 | session_length = max(2, round(np.random.exponential(session_avg_len))) 74 | cur_behavior = 'v' 75 | cur_item = np.random.choice(list(items.keys())) 76 | session = ['%s-%i' % (cur_behavior, cur_item)] 77 | for i in range(session_length - 1): 78 | next_behavior = 'p' if np.random.random() < .1 else 'v' 79 | next_item = gen_next_item(cur_behavior, cur_item, session, items) 80 | session.append('%s-%i' % (next_behavior, next_item)) 81 | cur_behavior, cur_item = next_behavior, next_item 82 | logs.append(session) 83 | return logs 84 | 85 | 86 | def save_item_info(items, filename): 87 | if os.path.isfile(filename): 88 | return 89 | 90 | with open(filename, 'wb') as f: 91 | pickle.dump(items, f) 92 | 93 | 94 | def save_log(logs): 95 | with open('./data/sim-log-session-%i.txt' % (len(logs)), 'w') as f: 96 | for session in logs: 97 | f.write('%s\n' % (' '.join(session))) 98 | 99 | 100 | def main(argv): 101 | n_items = 10000 102 | n_sessions = 100000 103 | 104 | item_info_filename = './data/item-info-%i.pck' % (n_items) 105 | items = gen_items(n_items=n_items, filename=item_info_filename) 106 | save_item_info(items, filename=item_info_filename) 107 | logs = gen_logs(items, n_sessions=n_sessions) 108 | save_log(logs) 109 | 110 | 111 | if __name__ == "__main__": 112 | main(sys.argv) 113 | 114 | 115 | -------------------------------------------------------------------------------- /behavior2vec/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ncu-dart/behavior2vec/20689603fc98f9f1e97cab4ef765b1deb5ab0d89/behavior2vec/tests/__init__.py -------------------------------------------------------------------------------- /bin/b2v-most-similar-behavior.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | ''' 5 | This script shows the most similar behavior based on the behavior2vec model. 6 | 7 | After installation, you may run the following command: 8 | 9 | $ b2v-most-similar-behavior.py [test-file] [model-file] [output-file] [k] [behavior-type] 10 | 11 | The [test-file] contains a list of query behaviors, one behavior per line. 12 | 13 | The [output-file] is the output file, which contains a list of the top [k] most simiar behaviors 14 | ''' 15 | 16 | import argparse 17 | import pickle 18 | import os 19 | import sys 20 | 21 | parser = argparse.ArgumentParser() 22 | parser.add_argument("-te", "--test_file", type=str, 23 | help="Test file") 24 | parser.add_argument("-m", "--model_file", type=str, 25 | help="Model file") 26 | parser.add_argument("-o", "--output_file", type=str, 27 | help="Output file") 28 | parser.add_argument("-k", "--k", type=int, default=1, 29 | help="Number of the most similar behaviors to return") 30 | parser.add_argument("-b", "--behavior_type", type=str, 31 | help="Behavior type") 32 | args = parser.parse_args() 33 | 34 | import behavior2vec 35 | 36 | 37 | def check_args(): 38 | if args.test_file is None or not os.path.isfile(args.test_file): 39 | print("test_file argument must be a valid file") 40 | parser.print_help() 41 | sys.exit(-1) 42 | 43 | if args.model_file is None or not os.path.isfile(args.model_file): 44 | print("model_file argument must be a valid file") 45 | parser.print_help() 46 | sys.exit(-1) 47 | 48 | 49 | def load_model(filename): 50 | with open(filename, 'rb') as f: 51 | m = pickle.load(f) 52 | return m 53 | 54 | 55 | def load_cur_behaviors(filename): 56 | cur_behaviors = [] 57 | with open(filename) as f: 58 | for line in f: 59 | cur_behaviors.append(line.strip()) 60 | return cur_behaviors 61 | 62 | 63 | def save_result(filename, most_similar_behaviors): 64 | with open(filename, 'w') as f_out: 65 | for behavior_score_pairs in most_similar_behaviors: 66 | for i, (behavior, score) in enumerate(behavior_score_pairs): 67 | if i == 0: 68 | f_out.write("%s:%f" % (behavior, score)) 69 | else: 70 | f_out.write(",%s:%f" % (behavior, score)) 71 | f_out.write("\n") 72 | 73 | 74 | def main(argv): 75 | check_args() 76 | 77 | most_similar_behaviors = [] 78 | m = load_model(args.model_file) 79 | cur_behaviors = load_cur_behaviors(args.test_file) 80 | for b in cur_behaviors: 81 | sim_behaviors, sim_scores = m.most_similar_behavior(b, target_behavior_type=args.behavior_type, k=args.k) 82 | most_similar_behaviors.append([pair for pair in zip(sim_behaviors, sim_scores)]) 83 | save_result(args.output_file, most_similar_behaviors) 84 | 85 | 86 | if __name__ == "__main__": 87 | main(sys.argv) 88 | -------------------------------------------------------------------------------- /bin/b2v-most-similar-item.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | ''' 5 | This script shows the most similar items based on the behavior2vec model. 6 | 7 | After installation, you may run the following command: 8 | 9 | $ b2v-most-similar-item.py [test-file] [model-file] [output-file] [k] 10 | 11 | The [test-file] contains a list of query items, one behavior per line. 12 | The [output-file] is the output file, which contains a list of the top [k] most simiar items 13 | ''' 14 | 15 | import argparse 16 | import os 17 | import pickle 18 | import sys 19 | 20 | 21 | parser = argparse.ArgumentParser() 22 | parser.add_argument("-te", "--test_file", type=str, 23 | help="Test file") 24 | parser.add_argument("-m", "--model_file", type=str, 25 | help="Model file") 26 | parser.add_argument("-o", "--output_file", type=str, 27 | help="Output file") 28 | parser.add_argument("-k", "--k", type=int, default=1, 29 | help="Number of the most similar behaviors to return") 30 | args = parser.parse_args() 31 | 32 | 33 | def check_args(): 34 | if args.test_file is None or not os.path.isfile(args.test_file): 35 | print("test_file argument must be a valid file") 36 | parser.print_help() 37 | sys.exit(-1) 38 | 39 | if args.model_file is None or not os.path.isfile(args.model_file): 40 | print("model_file argument must be a valid file") 41 | parser.print_help() 42 | sys.exit(-1) 43 | 44 | 45 | def load_model(filename): 46 | with open(filename, 'rb') as f: 47 | m = pickle.load(f) 48 | return m 49 | 50 | 51 | def load_cur_items(filename): 52 | cur_items = [] 53 | with open(filename) as f: 54 | for line in f: 55 | cur_items.append(line.strip()) 56 | return cur_items 57 | 58 | 59 | def save_result(filename, most_similar_items): 60 | with open(filename, 'w') as f_out: 61 | for item_score_pairs in most_similar_items: 62 | for i, (item, score) in enumerate(item_score_pairs): 63 | if i == 0: 64 | f_out.write("%s:%f" % (item, score)) 65 | else: 66 | f_out.write(",%s:%f" % (item, score)) 67 | f_out.write("\n") 68 | 69 | 70 | def main(argv): 71 | check_args() 72 | 73 | most_similar_items = [] 74 | m = load_model(args.model_file) 75 | cur_items = load_cur_items(args.test_file) 76 | for item in cur_items: 77 | sim_items, sim_scores = m.most_similar_item(item, k=args.k) 78 | most_similar_items.append([pair for pair in zip(sim_items, sim_scores)]) 79 | save_result(args.output_file, most_similar_items) 80 | 81 | 82 | if __name__ == "__main__": 83 | main(sys.argv) 84 | -------------------------------------------------------------------------------- /bin/b2v-train.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | ''' 5 | This script generates the behavior2vec model. 6 | 7 | After installation, you may run the following command: 8 | 9 | $ b2v-train.py [train-file] 10 | 11 | This will generate a model file of the name [train-file]-b2v-model.pck 12 | ''' 13 | 14 | # Hung-Hsuan Chen 15 | # Creation Date : 01-22-2018 16 | 17 | import argparse 18 | import pickle 19 | import os 20 | import sys 21 | 22 | parser = argparse.ArgumentParser() 23 | parser.add_argument("-tr", "--train_file", type=str, 24 | help="Training file") 25 | args = parser.parse_args() 26 | 27 | import behavior2vec 28 | 29 | 30 | def check_args(): 31 | if args.train_file is None or not os.path.isfile(args.train_file): 32 | print("train_file argument must be a valid file") 33 | parser.print_help() 34 | sys.exit(-1) 35 | 36 | 37 | def b2v_train(): 38 | m = behavior2vec.Behavior2Vec() 39 | m.train(args.train_file) 40 | return m 41 | 42 | 43 | def save_model(m): 44 | filename_prefix = os.path.splitext(os.path.basename(args.train_file))[0] 45 | with open('%s-b2v-model.pck' % (filename_prefix), 'wb') as f_out: 46 | pickle.dump(m, f_out) 47 | 48 | 49 | def main(argv): 50 | check_args() 51 | 52 | m = b2v_train() 53 | save_model(m) 54 | 55 | 56 | if __name__ == "__main__": 57 | main(sys.argv) 58 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | def readme(): 4 | with open('README.rst') as f: 5 | return f.read() 6 | 7 | setup(name='behavior2vec', 8 | version='0.1', 9 | description='The behavior2Vec model', 10 | long_description='This is a package to run the behavior2vec model', 11 | classifiers=[ 12 | 'Development Status :: 3 - Alpha', 13 | 'License :: OSI Approved :: MIT License', 14 | 'Programming Language :: Python :: 3.6', 15 | 'Topic :: Scientific/Engineering :: Artificial Intelligence', 16 | ], 17 | keywords='Word2Vec, Behavior2Vec', 18 | url='https://github.com/ncu-dart/behavior2vec', 19 | author='Hung-Hsuan Chen', 20 | author_email='hhchen@ncu.edu.tw', 21 | license='MIT', 22 | packages=['behavior2vec'], 23 | install_requires=[ 24 | 'numpy', 25 | 'scipy', 26 | 'gensim', 27 | ], 28 | include_package_data=True, 29 | zip_safe=False, 30 | test_suite='nose.collector', 31 | tests_require=['nose'], 32 | scripts=[ 33 | 'bin/b2v-train.py', 34 | 'bin/b2v-most-similar-behavior.py', 35 | 'bin/b2v-most-similar-item.py', 36 | ], 37 | ) 38 | --------------------------------------------------------------------------------