我正在寻找一种在SQL语句中查找范围的方法。
我的数据看起来像这样
COUNTRY PROTEIN MG
1 China 42.8 II
2 China 42.3 III
3 China 41.9 III
4 United States 40.0 IV
5 China 43.2 I
6 China 42.5 IV
7 China 42.9 III
8 China 45.9 VI
9 Japan 42.3 VI
10 United States 40.9 III
我目前正在运行这样的声明,我得到了蛋白质值的平均值,但我不知道如何处理罗马数字的范围
select COUNTRY, avg(PROTEIN), MG from data group by COUNTRY
我希望我的输出看起来像这样(不正确的数字只是一个例子)
COUNTRY MEAN MG_RANGE
China 42.3 I-III
United States 45.2 I-VI
我有这个文件作为CSV,所以我对R和Python的替代品开放,这将给我相同的输出。它也可以是数值,无论输出最简单。
答案 0 :(得分:2)
以下是一些解析和生成罗马数字的代码:http://pyparsing.wikispaces.com/file/view/romanNumerals.py/30112817/romanNumerals.py
将输入的罗马数字转换为整数(使用链接代码中的romanNumeral.parseString
),计算最小值和最大值以获取范围,然后在链接代码中使用makeRomanNumeral
来转换范围值回到罗马的名字。
或者,如果您没有那么多不同的罗马值来处理,只需定义一个将罗马数字映射到实际值的字典,您就可以跳过使用解析器。像这样:
romanLookup = {
'I' : 1,
'II' : 2,
'III' : 3,
'IV' : 4,
'V' : 5,
'VI' : 6,
'VII' : 7,
'VIII' : 8,
'IX' : 9,
'X' : 10,
'XI' : 11,
'XII' : 12,
'XIII' : 13,
'XIV' : 14,
'XV' : 15,
'XVI' : 16,
'XVII' : 17,
'XVIII' : 18,
'XIX' : 19,
'XX' : 20,
}
这是你的计划:
from itertools import groupby
from collections import namedtuple
DataRec = namedtuple("DataRec", "country protein mg")
#123456789012345678901234567890
# X X X X
data = """\
1 China 42.8 II
2 China 42.3 III
3 China 41.9 III
4 United States 40.0 IV
5 China 43.2 I
6 China 42.5 IV
7 China 42.9 III
8 China 45.9 VI
9 Japan 42.3 VI
10 United States 40.9 III""".splitlines()
suppress=object()
def splitAt(cols,fns):
last = 0
slices = []
for c in cols:
slices.append(slice(last,c))
last = c+1
return lambda s: [fn(s[sl]) for sl,fn in zip(slices,fns)
if fn is not suppress]
splitter = splitAt([2,16,24,28],
[suppress, str.strip, float, str.strip])
recs = [DataRec(*splitter(d)) for d in data]
romanLookup = {
'I' : 1,
'II' : 2,
'III' : 3,
'IV' : 4,
'V' : 5,
'VI' : 6,
'VII' : 7,
'VIII' : 8,
'IX' : 9,
'X' : 10,
'XI' : 11,
'XII' : 12,
'XIII' : 13,
'XIV' : 14,
'XV' : 15,
'XVI' : 16,
'XVII' : 17,
'XVIII' : 18,
'XIX' : 19,
'XX' : 20,
}
# sort and group data by country
recs.sort(key=lambda x: x.country)
grouped = groupby(recs, key=lambda x: x.country)
# for each country group, compute average protein and min/max mg
for country,countryRecs in grouped:
datatuples = list(countryRecs)
mg_vals = [r.mg for r in datatuples]
ave = sum(r.protein for r in datatuples)/len(datatuples)
min_mg = min(mg_vals, key=romanLookup.__getitem__)
max_mg = max(mg_vals, key=romanLookup.__getitem__)
if min_mg == max_mg:
print "%s, %.2f, %s" % (country, ave, min_mg)
else:
print "%s, %.2f, %s-%s" % (country, ave, min_mg, max_mg)
打印:
China, 43.07, I-VI
Japan, 42.30, VI
United States, 40.45, III-IV
答案 1 :(得分:2)
在R中, utils 包有一个非导出函数.roman2numeric()
,用于将字符罗马数字转换为它们各自的数值。我们可以将罗马字母转换为数字,然后汇总以查找国家/地区内的范围。
(dat$MG2 <- utils:::.roman2numeric(as.character(dat$MG))
# 2 3 3 4 1 4 3 6 6 3
dat
# COUNTRY PROTEIN MG MG2
# 1 China 42.8 II 2
# 2 China 42.3 III 3
# 3 China 41.9 III 3
# 4 UnitedStates 40.0 IV 4
# 5 China 43.2 I 1
# 6 China 42.5 IV 4
# 7 China 42.9 III 3
# 8 China 45.9 VI 6
# 9 Japan 42.3 VI 6
# 10 UnitedStates 40.9 III 3
并且(任意)找到每个国家MG2
的范围,我们可以做
aggregate(MG2 ~ COUNTRY, dat, range)
# COUNTRY MG2.1 MG2.2
# 1 China 1 6
# 2 Japan 6 6
# 3 UnitedStates 3 4