Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/290.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Pypark-markov模型的算法/编码帮助_Python_Algorithm_Machine Learning_Apache Spark_Pyspark - Fatal编程技术网

Python Pypark-markov模型的算法/编码帮助

Python Pypark-markov模型的算法/编码帮助,python,algorithm,machine-learning,apache-spark,pyspark,Python,Algorithm,Machine Learning,Apache Spark,Pyspark,我需要一些帮助来帮助我的大脑在spark(通过python)中设计一个(有效的)马尔可夫链。我已经尽我所能把它写得最好了,但是我的代码无法扩展。。基本上,对于不同的映射阶段,我编写了自定义函数,它们可以很好地处理几千个序列,但是当我们进入20000多个(我有一些高达800k)时,事情会变得很慢 对于那些不熟悉马尔可夫沼泽的人来说,这是它的要点 这是我的数据。。此时,我已经在RDD中获得了实际数据(没有标题) ID, SEQ 500, HNL, LNH, MLH, HML 我们看元组中的序列,所

我需要一些帮助来帮助我的大脑在spark(通过python)中设计一个(有效的)马尔可夫链。我已经尽我所能把它写得最好了,但是我的代码无法扩展。。基本上,对于不同的映射阶段,我编写了自定义函数,它们可以很好地处理几千个序列,但是当我们进入20000多个(我有一些高达800k)时,事情会变得很慢

对于那些不熟悉马尔可夫沼泽的人来说,这是它的要点

这是我的数据。。此时,我已经在RDD中获得了实际数据(没有标题)

ID, SEQ
500, HNL, LNH, MLH, HML
我们看元组中的序列,所以

(HNL, LNH), (LNH,MLH), etc..
我需要说到这一点。。在这里,我返回一个字典(针对每行数据),然后将其序列化并存储在内存数据库中

{500:
    {HNLLNH : 0.333},
    {LNHMLH : 0.333},
    {MLHHML : 0.333},
    {LNHHNL : 0.000},
    etc..
}
因此,本质上,每个序列与下一个序列相结合(HNL,LNH变为“HNLLNH”),然后对于所有可能的转换(序列的组合),我们计算它们的出现次数,然后除以转换的总数(本例中为3),得到它们的出现频率

上面有3个转变,其中一个是HNLNH。。对于HNLNH,1/3=0.333

作为一个侧面,我不确定它是否相关,但序列中每个位置的值是有限的。。第一个位置(H/M/L)、第二个位置(M/L)、第三个位置(H、M、L)

我的代码之前所做的是收集rdd(),并使用我编写的函数将其映射几次。这些函数首先将字符串转换为列表,然后将列表[1]与列表[2]合并,然后将列表[2]与列表[3]合并,最后将列表[3]与列表[4]合并,等等。。所以我就这样结束了

[HNLLNH],[LNHMLH],[MHLHML], etc..
然后,下一个函数从该列表中创建一个字典,使用列表项作为键,然后计算完整列表中该键的总出现次数,除以len(list)得到频率。然后,我将该字典和它的ID号一起打包到另一个字典中(生成第二个代码块,位于上面的a)

正如我所说,这对于小的ish序列很有效,但对于长度为100k+的列表就不太好了

另外,请记住,这只是一行数据。我必须在10-20k行数据中的任意位置执行此操作,数据行的长度在每行500-800000个序列之间变化

关于如何编写pyspark代码(使用API map/reduce/agg/etc.函数)来高效地完成这项工作,有什么建议吗

编辑 代码如下。。从底部开始可能是有道理的。请记住,我在学习这个(Python和Spark)的过程中,并不是为了谋生,所以我的编码标准并不高

def f(x):
    # Custom RDD map function
    # Combines two separate transactions
    # into a single transition state

    cust_id = x[0]
    trans = ','.join(x[1])
    y = trans.split(",")
    s = ''
    for i in range(len(y)-1):
        s= s + str(y[i] + str(y[i+1]))+","
    return str(cust_id+','+s[:-1])

def g(x):
    # Custom RDD map function
    # Calculates the transition state probabilities
    # by adding up state-transition occurrences
    # and dividing by total transitions
    cust_id=str(x.split(",")[0])
    trans = x.split(",")[1:]
    temp_list=[]
    middle = int((len(trans[0])+1)/2)
    for i in trans:
        temp_list.append( (''.join(i)[:middle], ''.join(i)[middle:]) )

    state_trans = {}
    for i in temp_list:
            state_trans[i] = temp_list.count(i)/(len(temp_list))

    my_dict = {}
    my_dict[cust_id]=state_trans
    return my_dict


def gen_tsm_dict_spark(lines):
    # Takes RDD/string input with format CUST_ID(or)PROFILE_ID,SEQ,SEQ,SEQ....
    # Returns RDD of dict with CUST_ID and tsm per customer
    #  i.e.  {cust_id : { ('NLN', 'LNN') : 0.33, ('HPN', 'NPN') : 0.66}

    # creates a tuple ([cust/profile_id], [SEQ,SEQ,SEQ])
    cust_trans = lines.map(lambda s: (s.split(",")[0],s.split(",")[1:]))

    with_seq = cust_trans.map(f)

    full_tsm_dict = with_seq.map(g)

    return full_tsm_dict


def main():
result = gen_tsm_spark(my_rdd)

# Insert into DB
for x in result.collect():
    for k,v in x.iteritems():
         db_insert(k,v)

你可以试试下面的方法。这在很大程度上取决于外部依赖,但如果您希望避免外部依赖,可以很容易地用一些标准Python库替换它

from __future__ import division
from collections import Counter
from itertools import product
from toolz.curried import sliding_window, map, pipe, concat
from toolz.dicttoolz import merge

# Generate all possible transitions 
defaults = sc.broadcast(dict(map(
    lambda x: ("".join(concat(x)), 0.0), 
    product(product("HNL", "NL", "HNL"), repeat=2))))

rdd = sc.parallelize(["500, HNL, LNH, NLH, HNL", "600, HNN, NNN, NNN, HNN, LNH"])

def process(line):
    """
    >>> process("000, HHH, LLL, NNN")
    ('000', {'LLLNNN': 0.5, 'HHHLLL': 0.5})
    """
    bits = line.split(", ")
    transactions = bits[1:]
    n = len(transactions) - 1
    frequencies = pipe(
        sliding_window(2, transactions), # Get all transitions
        map(lambda p: "".join(p)), # Joins strings
        Counter, # Count 
        lambda cnt: {k: v / n for (k, v) in cnt.items()} # Get frequencies
    )
    return bits[0], frequencies

def store_partition(iter):
    for (k, v) in iter:
        db_insert(k, merge([defaults.value, v]))

rdd.map(process).foreachPartition(store_partition)

由于您知道所有可能的转换,我建议使用稀疏表示并忽略零。此外,您可以用稀疏向量替换字典,以减少内存占用

您可以使用纯Pyspark实现此结果,我使用Pyspark实现了此功能

要创建频率,假设您已经实现了,这些是输入RDD

ID,SEQ

要获得像这样的频率,
(HNL,LNH),(LNH,MLH)…

inputRDD..map(lambda (k, list): get_frequencies(list)).flatMap(lambda x: x) \
        .reduceByKey(lambda v1,v2: v1 +v2)


get_frequencies(states_list):
    """
    :param states_list: Its a list of Customer States.
    :return: State Frequencies List.
    """
    rest = []
    tuples_list = []

    for idx in range(0,len(states_list)):
        if idx + 1 < len(states_list):
            tuples_list.append((states_list[idx],states_list[idx+1]))

    unique = set(tuples_list)

    for value in unique:
        rest.append((value, tuples_list.count(value)))
    return rest

在此之后,您可以将结果
RDDs
转换为
Dataframes
,或者您可以使用
rddsmappartitions

collect()将rdd转换为
DB
,然后使用我编写的函数将其映射几次
您不应该这样做,您需要一直保持在rdd内,或者您不需要Spark。你能发布你的实际代码吗?是的,当我把我的性能问题追溯到我自己的函数时,我意识到了这一点:)不幸的是,代码被封装在一个大得多的程序中,提取它将有点困难和混乱,但我会尽我所能。。请记住,无论如何我都不是python方面的专家……)将代码作为edit@nameBrandon什么是db_insert?你在哪里定义它?db_insert是什么?它是在哪里定义的?@DimKoim
db_insert
来自原始帖子。它不是一个库函数。
inputRDD..map(lambda (k, list): get_frequencies(list)).flatMap(lambda x: x) \
        .reduceByKey(lambda v1,v2: v1 +v2)


get_frequencies(states_list):
    """
    :param states_list: Its a list of Customer States.
    :return: State Frequencies List.
    """
    rest = []
    tuples_list = []

    for idx in range(0,len(states_list)):
        if idx + 1 < len(states_list):
            tuples_list.append((states_list[idx],states_list[idx+1]))

    unique = set(tuples_list)

    for value in unique:
        rest.append((value, tuples_list.count(value)))
    return rest
((HNL, LNH), 98),((LNH, MLH), 458),() ......