繁体   English   中英

获取不同ID上的消息密度

[英]Get density of messages on distinct ID's

想象一下,有10所房屋,其中可能有一个到无限数量的人。 这些人每个人都发送许多消息,其中包含他们的用户名和门牌号。 这可以是1到无限数量的消息。 我想知道每个人针对每所房屋发送的平均邮件数量,以便以后绘制哪个房屋获得的平均邮件数量最多。

现在,我已经从概念上进行了解释,房屋不是房屋,而是纬度,从f.ex -90到-89等。一个人可以从不同的房屋发送消息。

所以我有一个包含纬度和senderID的数据库。 我想绘制纬度密度pr唯一senderID:

在一个时间间隔内每个纬度上的Number of rows/Number of unique userids

这是一个示例输入:

lat = [-83.76, -44.88, -38.36, -35.50, -33.99, -31.91, -27.56, -22.95,
        40.72,  47.59,  54.42,  63.84,  76.77, 77.43, 78.54]

userid= [5, 7, 6, 6, 6, 6, 5, 2,
         2, 2, 1, 5, 10, 9 ,8]

以下是相应的密度:

-80 to -90: 1
-40 to -50: 1
-30 to -40: 4
-20 to -30: 1
  40 to 50: 2
  50 to 60: 1
  60 to 70: 1
  70 to 80: 1

其他输入:

lat = [70,70,70,70,70,80,80,80]
userid = [1,2,3,4,5,1,1,2]

纬度70的密度为1,而纬度80的密度为1.5。

如果我要通过数据库查询/伪代码执行此操作,则会执行以下操作:

SELECT count(latitude) FROM messages WHERE latitude < 79 AND latitude > 69
SELECT count(distinct userid) FROM messages WHERE latitude < 79 AND latitude > 69

然后,密度将为count(latitude)/count(distinct userid) -也将被解释为totalmessagesFromCertainLatitude / distinctUserIds。 将在-90到90的间隔内重复此操作,即-90<latitude<-8989<latitude<90

在这方面寻求任何帮助可能很遥远,但是我确信自己没有错误,但我无法整理思路来做到这一点。 我会为任何事情感到高兴。 如果不清楚,对不起。

因为它很好地包装在熊猫的内置文件中,所以对于大数据集而言,在熊猫中可能很快。

lat = [-83.76, -44.88, -38.36, -35.50, -33.99, -31.91, -27.56, -22.95,
        40.72,  47.59,  54.42,  63.84,  76.77, 77.43, 78.54]

userid= [5, 7, 6, 6, 6, 6, 5, 2,
         2, 2, 1, 5, 10, 9 ,8]
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
from matplotlib.collections import PatchCollection
from math import floor

df = pd.DataFrame(zip(userid,lat), columns = ['userid','lat']
)
df['zone'] = map(lambda x: floor(x) * 10,df.lat/10) # for ten-degree zones
zonewidth=10
#df['zone'] = map(floor, df.lat) # for one-degree zones
#zonewidth=1 # ditto

dfz = df.groupby('zone') #returns a dict of dataframes

#for k, v in dfz: # useful for exploring the GroupBy object
#    print(k, v.userid.values, float(len(v.userid.values))/len(set(v.userid.values))) 

p = [(k, float(len(v.userid.values))/len(set(v.userid.values))) for k, v in dfz]

# plotting could be tightened up -- PatchCollection?  
R = [Rectangle((x, 0), zonewidth, y, facecolor='red', edgecolor='black',fill=True) for x, y in p]
fig, ax = plt.subplots()
for r in R:
    ax.add_patch(r)
plt.xlim((-90, 90))
tall = max([r.get_height() for r in R])
plt.ylim((0, tall + 0.5))
plt.show()

对于第一组测试数据:

在此处输入图片说明

我不是100%肯定我已经理解了您想要的输出,但是这会生成一个阶梯式,累积直方图,x轴为纬度(合并),y轴为您在上面定义的密度。

从示例代码中,您已经安装了numpy并很乐意使用它。 我将采用的方法是获取两个数据集,就像SQL示例将返回的数据集一样,然后使用它们来获取密度然后进行绘图。 使用您现有的纬度/用户ID数据格式-可能看起来像这样

编辑:从此处删除了代码的第一个版本以及一些注释,这些注释在OP中进行了澄清和问题编辑之后是多余的


以下评论和OP澄清-我认为这是所需要的:

import numpy as np
import matplotlib.pyplot as plt
from itertools import groupby

import numpy as np
import matplotlib.pyplot as plt
from itertools import groupby

def draw_hist(latitudes,userids):
    min_lat = -90
    max_lat = 90
    binwidth = 1

    bin_range = np.arange(min_lat,max_lat,binwidth)

    all_rows = zip(latitudes,userids)
    binned_latitudes = np.digitize(latitudes,bin_range)
    all_in_bins = zip(binned_latitudes,userids)
    unique_in_bins = list(set(all_in_bins))
    all_in_bins.sort()
    unique_in_bins.sort()

    bin_count_all = []
    for bin, group in groupby(all_in_bins, lambda x: x[0]):
        bin_count_all += [(bin, len([k for k in group]))]

    bin_count_unique = []
    for bin, group in groupby(unique_in_bins, lambda x: x[0]):
        bin_count_unique += [(bin, len([ k for k in group]))]        

    # bin_count_all and bin_count_unique now contain the data
    # corresponding to the SQL / pseudocode in your question
    # for each latitude bin

    bin_density = [(bin_range[b-1],a*1.0/u) for ((b,a),(_,u)) in zip(bin_count_all, bin_count_unique)]

    bin_density =  np.array(bin_density).transpose()

    # plot as standard bar - note you can put uneven widths in 
    # as an array-like here if necessary
    # the * simply unpacks the x and y values from the density
    plt.bar(*bin_density, width=binwidth)
    plt.show()
    # can save away plot here if desired


latitudes = [-70.5, 5.3, 70.32, 70.43, 5, 32, 80, 80, 87.3]
userids = [1,1,2,2,4,5,1,1,2]

draw_hist(latitudes,userids)

OP数据集上具有不同bin宽度的示例输出

箱宽度为0.1、1和10的输出

我认为这可以解决问题,尽管它根本没有效率:

con = lite.connect(databasepath)
binwidth = 1
latitudes = []
userids = []
info = []
densities = []
with con:
    cur = con.cursor()
    cur.execute('SELECT latitude, userid FROM dynamicMessage')
    con.commit()
    print "executed"
    while True:
        tmp = cur.fetchone()
        if tmp != None:
            info.append([float(tmp[0]),float(tmp[1])])
        else:
            break
    info = sorted(info, key=itemgetter(0))
    for x in info:
        latitudes.append(x[0])
        userids.append(x[1])
    x = 0
    latitudecount = 0
    for b in range(int(min(latitudes)),int(max(latitudes))+1):
        numlatitudes = sum(i<b for i in latitudes)
        if numlatitudes > 1:
            tempdensities = latitudes[0:numlatitudes]
            latitudes = latitudes[numlatitudes:]
            tempuserids = userids[0:numlatitudes]
            userids = userids[numlatitudes:]
            density = numlatitudes/len(list(set(tempuserids)))
            if density>1:
                tempdensities = [b]*int(density)
                densities.extend(tempdensities)
    plt.hist(densities, bins=len(list(set(densities))))
    plt.savefig('latlongstats'+'t'+str(time.strftime("%H:%M:%S")), format='png')

在绘制所需的直方图方面,以下内容并不是一个完整的解决方案,但是我认为仍然值得举报

  1. 解决方案的主要部分是,我们扫描元组数组以选择所需范围内的元组,然后进行计数

    • 所选元组的数量
    • 唯一ID,使用的技巧包括创建一个集(这会自动丢弃重复项)并计算其数值

    最终,如果不同ID的计数为零,我们将返回所需比率或零。

     def ratio(d, mn, mx): tmp = [(lat, uid) for lat, uid in d if mn <= lat < mx] nlats, nduids = len(tmp), len({t[1] for t in tmp}) return 1.0*nlats/nduids if nduids>0 else 0 
  2. 输入数据,并通过zip分配给元组列表

     lat = [-83.76, -44.88, -38.36, -35.50, -33.99, -31.91, -27.56, -22.95, -19.00, -12.32, -6.14, -1.11, 4.40, 10.23, 19.40, 31.18, 40.72, 47.59, 54.42, 63.84, 76.77] userid= [52500.0, 70100.0, 35310.0, 47776.0, 70100.0, 30991.0, 37328.0, 25575.0, 37232.0, 6360.0, 52908.0, 52908.0, 52908.0, 77500.0, 345.0, 6360.0, 3670.0, 36690.0, 3720.0, 2510.0, 2730.0] data = zip(lat,userid) 
  3. 垃圾桶的准备

     extremes = range(-90,91,10) intervals = zip(extremes[:-1],extremes[1:]) 
  4. 实际计算中,结果是可以传递给相关pyplot函数的float列表

     ratios = [ratio(data,*i) for i in intervals] print ratios # [1.0, 0, 0, 0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 0, 1.0, 1.0, 1.0, 1.0, 1.0, 0] 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM