Как структурировать и получить доступ к таблице данных, чтобы я мог легко сравнивать подмножества в Python 3.5?

  1. есть ли более подходящие для Python способ сделать это?
  2. что создание этого предупреждения UserWarning: Boolean Series key will be reindexed to match DataFrame index. "DataFrame index.", UserWarning и стоит ли мне беспокоиться об этом?

у меня есть csv-файл с 3 столбцами: 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)

конечная цель состоит в том, чтобы сравнить пересечение лиц между 2 последовательных периодов с набором лиц в первом период.

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

Edit: я получил его для работы с:

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
...

но это очень медленно и уродливо...по текущему курсу мой расчет задней части конверта оценивает его примерно в 22 часа для 2-летней партии данных.

2 ответов


По общему признанию, Я никогда не использовал панд, поэтому это может быть не идиоматично. Это просто использует базовые структуры 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] поиск во внутреннем цикле. Он должен работать значительно быстрее, чем исходный код.


Я бы не обязательно уволил панд здесь. Это зависит от нескольких вещей. Я не думаю, что 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, чтобы справиться с этим. Аналогично, вы можете добавить код для обработки дней без присутствия человека, и есть способы справиться с и это тоже.