我应该如何构建和访问数据表,以便我可以在Python 3.5中轻松比较子集?

时间:2016-02-22 19:44:34

标签: python python-3.x pandas dataframe

  1. 有更快,更pythonic的方式吗?
  2. 是什么 生成此警告UserWarning: Boolean Series key will be reindexed to match DataFrame index. "DataFrame index.", UserWarning 我应该关注它吗?
  3. 我有一个包含3列的csv文件:org,month,person。

    | org |    month   | person |
    | --- | ---------- | ------ |
    |   1 | 2014-01-01 |    100 |
    |   1 | 2014-01-01 |    200 |
    |   1 | 2014-01-02 |    200 |
    |   2 | 2014-01-01 |    300 |
    

    我已使用以下内容阅读了pandas.core.frame.DataFrame

    data = pd.read_csv('data_base.csv', names=['month', 'org', 'person'], skiprows=1)
    

    最终目标是将两个连续时期之间的人与第一个时期的一组人进行比较。

    org: 1, month: 2014-01-01, count(intersection((100, 200), 200)) / len(set(100, 200)) == 0.5
    

    编辑:我让它与之合作:

    import pandas as pd
    import sys
    
    data = pd.read_csv('data_base.csv', names=['month', 'org', 'person'], skiprows=1)
    data.sort_values(by=['org', 'month', 'person'])
    
    results = {}
    for _org in set(data.org):
        results[_org] = {}
        months = sorted(list(set(data[data.org == _org].month)))
        for _m1, _m2 in zip(months, months[1:]):
            _s1 = set(data[data.org == _org][data.month == _m1].person)
            _s2 = set(data[data.org == _org][data.month == _m2].person)
            results[_org][_m1] = float(len(_s1 & _s2) / len(_s1))
            print(str(_org) + '\t' + str(_m1) + '\t' + str(_m2) + '\t' + str(round(results[_org][_m1], 2)))
            sys.stdout.flush()
    

    产生如下输出:

    UserWarning: Boolean Series key will be reindexed to match DataFrame index. "DataFrame index.", UserWarning
    5640    2014-01-01  2014-02-01  0.75
    5640    2014-02-01  2014-03-01  0.36
    5640    2014-03-01  2014-04-01  0.6
    ...
    

    但它的真的很慢,有点丑陋 ...按照目前的速度,我的背包计算估算为2年约22小时批量数据。

2 个答案:

答案 0 :(得分:3)

不可否认,我从未使用熊猫,所以这可能不是惯用语。这只是使用基本的Python结构。

import collections
org_month_dict = collections.defaultdict(set)

# put the data into a simple, indexed data structure
for index, row in data.iterrows():
    org_month_dict[row['org'], row['month']].add(row['person'])

orgs = set(data.org)
months = sorted(set(data.months))
for org in orgs:
    for mindex in range(len(months)-1):
        m1 = months[mindex]
        m2 = months[mindex+1]
        print org_month_dict[org, m2] & org_month_dict[org, m1] # persons in common between month 1 and 2

这会在org_month_dict中创建一个“缓存”查找表,该表按组织和月份编制索引,从而避免在内循环中执行昂贵的data[data.org == _org][data.month == _m1]查找。它的运行速度应该比原始代码快得多。

答案 1 :(得分:1)

我不一定会在这里解雇大熊猫。这取决于一些事情。我不认为pandas将是一种非常紧凑的存储数据的方式,尽管它具有自动压缩和稀疏存储选项,这在很大程度上缓解了这一点。我希望速度非常合理,但你真的必须对你的数据进行测试才能确定。

它确实提供了(在我看来)一种更方便的方式来存储您的数据,并提供了处理日期的便捷方式。完成后,您可以以表格形式输出结果。

首先,我将稍微扩展数据以更好地展示问题。

    org       month  person
0     1  2014-01-01     100
1     1  2014-01-01     200
2     1  2014-01-02     200
3     1  2014-01-03     300
4     1  2014-01-03     100
5     1  2014-01-04     200
6     1  2014-01-04     100
7     1  2014-01-04     300
8     2  2014-01-01     100
9     2  2014-01-01     200
10    2  2014-01-02     300
11    2  2014-01-02     400
12    2  2014-01-03     100
13    2  2014-01-04     200
14    2  2014-01-04     100

然后,你可以这样做:

df['one'] = 1
df = df.set_index(['org','month','person']).unstack('person')
numer = ((df==df.shift(-1)) & (df.notnull())).sum(axis=1)
denom = df.notnull().sum(axis=1)

df['numer'] = numer
df['denom'] = denom
df['ratio'] = numer / denom

               one             numer denom     ratio
person         100 200 300 400                      
org month                                           
1   2014-01-01   1   1 NaN NaN     1     2  0.500000
    2014-01-02 NaN   1 NaN NaN     0     1  0.000000
    2014-01-03   1 NaN   1 NaN     2     2  1.000000
    2014-01-04   1   1   1 NaN     2     3  0.666667
2   2014-01-01   1   1 NaN NaN     0     2  0.000000
    2014-01-02 NaN NaN   1   1     0     2  0.000000
    2014-01-03   1 NaN NaN NaN     1     1  1.000000
    2014-01-04   1   1 NaN NaN     0     2  0.000000

我在这里忽略了一些细节,比如org 1和org 2之间的断点,但你可以添加一个groupby来处理这个问题。同样,您可能希望添加代码来处理没有人在场的日子,并且还有办法处理它。