【问题标题】:Python, dictionaries, and chi-square contingency tablePython、字典和卡方列联表
【发布时间】:2010-06-13 08:49:12
【问题描述】:

这是一个我已经绞尽脑汁很久的问题,所以任何帮助都会很棒。我有一个文件,其中包含以下格式的几行(单词,单词出现的时间,以及在给定实例中包含给定单词的文档的频率)。下面是输入文件的示例。

#inputfile
<word, time, frequency>
apple, 1, 3
banana, 1, 2
apple, 2, 1
banana, 2, 4
orange, 3, 1

我有下面的 Python 类,我用来创建二维字典来存储上述文件,使用作为键,频率作为值:

class Ddict(dict):
    '''
    2D dictionary class
    '''
    def __init__(self, default=None):
            self.default = default

    def __getitem__(self, key):
            if not self.has_key(key):
                self[key] = self.default()
            return dict.__getitem__(self, key)


wordtime=Ddict(dict) # Store each inputfile entry with a <word,time> key
timeword=Ddict(dict) # Store each inputfile entry with a <time,word> key

# Loop over every line of the inputfile
for line in open('inputfile'):
    word,time,count=line.split(',')

    # If <word,time> already a key, increment count
    try:
        wordtime[word][time]+=count
    # Otherwise, create the key
    except KeyError:
        wordtime[word][time]=count

    # If <time,word> already a key, increment count     
    try:
        timeword[time][word]+=count
    # Otherwise, create the key
    except KeyError:
        timeword[time][word]=count

我的问题与在迭代此 2D 字典中的条目时计算某些事物有关。对于每个时间 't' 的每个单词 'w',计算:

  1. 具有的文档数 单词“w”时间“t”内。 (一)
  2. 没有的文档数 单词“w”时间“t”内。 (b)
  3. 具有的文档数 单词'w'时间't'之外。 (c)
  4. 没有的文档数 单词'w'时间't'之外。 (d)

上面的每个项目代表每个单词和时间的卡方列联表的一个单元格。所有这些都可以在一个循环中计算,还是需要一次完成一个?

理想情况下,我希望输出如下所示,其中 a、b、c、d 是上面计算的所有项目:

print "%s, %s, %s, %s" %(a,b,c,d)

在上述输入文件的情况下,尝试在时间 '1' 查找单词 'apple' 的列联表的结果将是 (3,2,1,6)。我将解释如何计算每个单元格:

  • “3”个文档中包含“apple” 时间“1”。
  • 在时间内有“2”个文档 不包含“apple”的“1”。
  • 有“1”个文档包含 'apple' 在时间 '1' 之外。
  • 时间外有6个文件 '1' 不包含单词 '苹果' (1+4+1)。

【问题讨论】:

  • dict.has_key() 已过时、已弃用且速度较慢。而不是d.has_key(k) 使用k in d。另一张海报提到了defaultdict。考虑更新您正在使用的教程/书籍。
  • @JohnMachin 谢谢,我一定会牢记这一点。

标签: python dictionary discrete-mathematics


【解决方案1】:

apple/1 的 4 个数字加起来是 12,比观察总数 (11) 还多!在时间 '1' 之外只有 5 个文档不包含单词 'apple'。

您需要将观察结果划分为 4 个不相交的子集:
a:苹果和 1 => 3
b: 非苹果和 1 => 2
c: 苹果而不是-1 => 1
d: not-apple 和 not-1 => 5

这里有一些代码显示了一种方法:

from collections import defaultdict

class Crosstab(object):

    def __init__(self):
        self.count = defaultdict(lambda: defaultdict(int))
        self.row_tot = defaultdict(int)
        self.col_tot = defaultdict(int)
        self.grand_tot = 0

    def add(self, r, c, n):
        self.count[r][c] += n
        self.row_tot[r] += n
        self.col_tot[c] += n
        self.grand_tot += n

def load_data(line_iterator, conv_funcs):
    ct = Crosstab()
    for line in line_iterator:
        r, c, n = [func(s) for func, s in zip(conv_funcs, line.split(','))]
        ct.add(r, c, n)
    return ct

def display_all_2x2_tables(crosstab):
    for rx in crosstab.row_tot:
        for cx in crosstab.col_tot:
            a = crosstab.count[rx][cx]
            b = crosstab.col_tot[cx] - a
            c = crosstab.row_tot[rx] - a
            d = crosstab.grand_tot - a - b - c
            assert all(x >= 0 for x in (a, b, c, d))
            print ",".join(str(x) for x in (rx, cx, a, b, c, d))

if __name__ == "__main__":

    # inputfile
    # <word, time, frequency>
    lines = """\
    apple, 1, 3
    banana, 1, 2
    apple, 2, 1
    banana, 2, 4
    orange, 3, 1""".splitlines()

    ct = load_data(lines, (str.strip, int, int))
    display_all_2x2_tables(ct)

这是输出:

orange,1,0,5,1,5
orange,2,0,5,1,5
orange,3,1,0,0,10
apple,1,3,2,1,5
apple,2,1,4,3,3
apple,3,0,1,4,6
banana,1,2,3,4,2
banana,2,4,1,2,4
banana,3,0,1,6,4

【讨论】:

  • 这个好办法。我特别喜欢load_data 中的技术——line_iteratorconv_funcs 的使用。
猜你喜欢
  • 2015-03-21
  • 1970-01-01
  • 1970-01-01
  • 2018-02-06
  • 1970-01-01
  • 1970-01-01
  • 2018-12-26
  • 2021-06-28
  • 2021-03-12
相关资源
最近更新 更多