【问题标题】:Create advanced frequency table with Python使用 Python 创建高级频率表
【发布时间】:2015-08-20 17:44:33
【问题描述】:

我正在尝试基于带有 pandas 和 Python 的数据框制作频率表。其实和a previous question of mine which used R一模一样。

假设我在 pandas 中有一个如下所示的数据框(实际上数据框要大得多,但出于说明目的,我限制了行数):

node    |   precedingWord
-------------------------
A-bom       de
A-bom       die
A-bom       de
A-bom       een
A-bom       n
A-bom       de
acroniem    het
acroniem    t
acroniem    het
acroniem    n
acroniem    een
act         de
act         het
act         die
act         dat
act         t
act         n

我想使用这些值来计算每个节点的precedingWords,但带有子类别。例如:要添加值的一列标题为neuter,另一列为non-neuter,最后一列为restneuter 将包含所有值,previousWord 是以下值之一:t,het,datnon-neuter 将包含 dedie,rest 将包含不属于 neuternon-neuter 的所有内容。 (如果这可以是动态的,那就太好了,换句话说,rest 使用某种用于中性和非中性的反转变量。或者只是从长度中减去中性和非中性的值具有该节点的行。)

示例输出(在一个新的数据帧中,比如说freqDf,看起来像这样:

node    |   neuter   | nonNeuter   | rest
-----------------------------------------
A-bom       0          4             2
acroniem    3          0             2
act         3          2             1

我找到了an answer to a similar question,但用例并不完全相同。在我看来,在这个问题中,所有变量都是独立的。但是,在我的情况下,很明显我有多行具有相同的节点,应该将它们全部降低到一个单一的频率 - 如上面的预期输出所示。

我认为是这样的(未经测试):

def specificFreq(d):  
    for uniqueWord in d['node']
        return pd.Series({'node': uniqueWord ,
            'neuter': sum(d['node' == uniqueWord] & d['precedingWord'] == 't|het|dat'),
            'nonNeuter':  sum(d['node' == uniqueWord] & d['precedingWord'] == 'de|die'),
            'rest': len(uniqueWord) - neuter - nonNeuter}) # Length of rows with the specific word, distracted by neuter and nonneuter values above

df.groupby('node').apply(specificFreq)

但我非常怀疑这是做这种事情的正确方法。

【问题讨论】:

    标签: python pandas dataframe word-frequency


    【解决方案1】:

    按照R方案中的建议,可以先改名字,再进行交叉制表:

    df.loc[df.precedingWord.isin(neuter), "gender"] = "neuter"
    df.loc[df.precedingWord.isin(non_neuter), "gender"] = "non_neuter"
    df.loc[df.precedingWord.isin(neuter + non_neuter)==0, "gender"] = "rest"
    # neuter + non_neuter is the concatenation of both lists.
    
    pd.crosstab(df.node, df.gender)
    gender    neuter  non_neuter  rest
    node                              
    A-bom          0           4     2
    acroniem       3           0     2
    act            3           2     1
    

    这个更好,因为如果neuternon_neuter 中的单词在precedingword 中不存在,它就不会像以前的解决方案那样引发KeyError


    以前的解决方案,不太干净。

    根据您的数据框,您可以制作一个简单的交叉表:

    ct = pd.crosstab(df.node, df.precedingWord) 
    

    给出:

    pW        dat  de  die  een  het  n  t
    node                                  
    A-bom       0   3    1    1    0  1  0
    acroniem    0   0    0    1    2  1  1
    act         1   1    1    0    1  1  1
    

    然后,您只想将某些列相加:

    neuter = ["t", "het", "dat"]
    non_neuter = ["de","die"]
    freqDf = pd.DataFrame()
    
    freqDf["neuter"] = ct[neuter].sum(axis=1)
    ct.drop(neuter, axis=1, inplace=1)
    
    freqDf["non_neuter"] = ct[non_neuter].sum(axis=1)
    ct.drop(non_neuter, axis=1, inplace=1)
    
    freqDf["rest"] = ct.sum(axis=1)
    

    给你freqDf

              neuter  non_neuter  rest
    node                              
    A-bom          0           4     2
    acroniem       3           0     2
    act            3           2     1
    

    HTH

    【讨论】:

    • 谢谢。我想我明白发生了什么:创建一个所有单词的频率表。然后,从那个表格中得出总和。首先是中性病例,然后是非中性病例。每次操作后,删除所有相关列,然后最后计算所有剩余列。正确的?一个问题。 axis=1 是做什么的?另外,我很快在 Python 3.4.3 中尝试了这个,我得到了 freqDf 没有定义的错误。我应该先创建一个名为 freqDf 的新表吗?
    • @BramVanroy,是的,这正是它正在做的事情。 axis=1 是选择维度(列或行,因此 1 表示列,0 表示行),您将沿着该维度进行操作。
    • @BramVanroy,我为freqDf 编辑过,我忘记复制/粘贴一行,但是是的,您需要声明它。
    • 到目前为止这很好,但是有一个问题。在使用任一解决方案时,当找不到neuter 中的元素时,Python 将抛出索引错误。例如:将中性更改为neuter = ["het", "banana"]。虽然是一个虚构的例子,但它可能会在未来引发问题。
    • @BramVanroy,第一个解决方案确实有KeyError,但第二个解决方案没有。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-03
    • 2016-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-07
    相关资源
    最近更新 更多