使用groupby和pandas后查找唯一列元素的数量

时间:2015-11-01 23:34:48

标签: python dictionary pandas count

我有一个如下设置的数据集:

rows = [
    ('us', 0, 'ca', None, 94107, -100),
    ('ca', 1, None, 'bc', 94107, -100),
    ('us', 0, 'ca', None, 94106, 0),
    ('us', 0, 'ca', None, 94107, 0),
    ('ca', 1, None, 'bc', 94107, 0),
    ('ca', 1, None, 'bc', 94107, 0),
    ('us', 0, 'ca', None, 94107, 100),
    ('us', 0, 'ca', None, 94107, 100)
]

我想分组:(country, state/provence, zip),然后在分组完成后找到Option列的计数,最后转换为dict。

理想情况下,我希望将dict格式化为:

{
    ('us', 'ca', 94107): {100: 2, -100: 1, 0: 1}, 
    ('us', 'ca', 94106): {0: 1},  
    ('ca', 'bc', 94107): {-100: 1, 0: 2}
}

到目前为止,我有以下代码:

# build the data frame
df = pd.DataFrame(rows, columns=['Country', 'LocFilter', 'State', 'Provence', 'Zip', 'Option'])

# consolidate "State" and "Provence" into "MainProvence" based on "LocFilter"
df['MainProvence'] = df.apply(lambda row: (row['Provence'] if row['LocFilter'] == 1 else row['State']), axis=1)

# group by and find distribution
distribution = df.groupby(by=['Country', 'MainProvence','Zip', 'Option'])['Option'].count()
# print the result
print distribution

这给了我以下 - 看起来不错:

Country  MainProvence  Zip    Option
ca       bc            94107  -100      1
                               0        2
us       ca            94106   0        1
                       94107  -100      1
                               0        1
                               100      2
Name: Option, dtype: int64

但是,当我将其转换为词典时:

print distribution.to_dict()

我明白了:

{
    ('us', 'ca', 94107, 100): 2, 
    ('us', 'ca', 94106, 0): 1, 
    ('us', 'ca', 94107, -100): 1, 
    ('ca', 'bc', 94107, 0): 2, 
    ('ca', 'bc', 94107, -100): 1, 
    ('us', 'ca', 94107, 0): 1
}

根据我如何形成groupby,这是可以理解的。我显然可以在python中操作返回的dict来获取我想要的格式 - 但有没有办法使用pandas获取这种格式?

1 个答案:

答案 0 :(得分:1)

这非常简单。尝试:

distribution.unstack(level=['Option']).to_dict(orient='index')

获得

{('ca', 'bc', 94107): {-100: 1.0, 0: 2.0, 100: nan},
 ('us', 'ca', 94106): {-100: nan, 0: 1.0, 100: nan},
 ('us', 'ca', 94107): {-100: 1.0, 0: 1.0, 100: 2.0}}

我认为放弃nan s不应该造成太大的不便。

PS。考虑使用:

df['MainProvence'] = df['State'].fillna(df['Provence'])

取代

df['MainProvence'] = df.apply(lambda row: (row['Provence'] if row['LocFilter'] == 1 else row['State']), axis=1)

PPS。 orient kwarg需要Pandas 0.17才能在to_dict()内工作。