在SQL中查找罗马数字的范围

时间:2014-10-01 00:11:13

标签: python sql r range average

我正在寻找一种在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的替代品开放,这将给我相同的输出。它也可以是数值,无论输出最简单。

2 个答案:

答案 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