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