[英]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<-89
到89<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宽度的示例输出
我认为这可以解决问题,尽管它根本没有效率:
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')
在绘制所需的直方图方面,以下内容并不是一个完整的解决方案,但是我认为仍然值得举报
解决方案的主要部分是,我们扫描元组数组以选择所需范围内的元组,然后进行计数
最终,如果不同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
输入数据,并通过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)
垃圾桶的准备
extremes = range(-90,91,10) intervals = zip(extremes[:-1],extremes[1:])
实际计算中,结果是可以传递给相关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.