Вы можете использовать collections.defaultdict
для создания словаря с колонками а как ключи и каждый с defaultdict(list)
для значения. Вложенный defaultdict(list)
использует столбец B в качестве ключей и список значений из столбца C.
Следующий код создает такой словарь, а затем использует его, чтобы произвести подсчет пройденных элементов столбца B для каждого столбца A.
from pandas import read_csv
from collections import defaultdict
data = defaultdict(lambda : defaultdict(list))
df = read_csv('datafile', sep='\t')
for a, b, c in df.values:
data[a][b].append(c)
#from pprint import pprint
#pprint(data.items())
# output the total number of passes for each "A" in which all runs of "B" passed.
result_counts = {a: sum(1 for b in data[a] if all(c=='Passed' for c in data[a][b])) for a in data}
print('Counts: {}'.format(result_counts))
# output for each "A" a list of all passed "B"s.
result_passed = {a: list(b for b in data[a] if all(c=='Passed' for c in data[a][b])) for a in data}
print('Passed: {}'.format(result_passed))
Выход
Counts: {'LE': 6, 'FT': 5, 'CD': 1}
Passed: {'LE': ['DEL-14', 'PRO-45', 'PRO-51', 'GR-19', 'GR-22', 'GR-20'], 'FT': ['PRO-19', 'PRO-18', 'GR-01', 'GR-03', 'GR-02'], 'CD': ['GR-09']}
Update
Что касается проблемы, с которой вы сталкиваетесь при итерации по кадру данных, есть две проблемы, которые я вижу. Во-первых, разделитель полей по умолчанию для read_csv
является запятой. Кажется, что ваши данные разделены на вкладку. Во-вторых, вы не можете выполнять итерацию непосредственно по кадру данных. Попробуйте использовать один из следующих вариантов (я предлагаю несколько, поскольку они имеют разные характеристики):
df = pd.read_csv('SIT Req.tx', sep='\t') # note use of sep
for a, b, c in df.values:
...
# or
for i, a, b, c in df.itertuples():
...
# or
for i, row in df.iterrows():
a, b, c = row
...
Update 2
Вот длинная версия словаря понимания, который выбирает те элементы из столбца B для которых все тесты прошли:
result_passed = {}
for a in data:
result_passed[a] = []
for b in data[a]:
passed = True
for c in data[a][b]:
if c != 'Passed':
passed = False
break
if passed:
result_passed[a].append(b)
Вы можете получить лучшее понимание того, как это работает, глядя на содержание и структуру data
словаря:
>>> from pprint import pprint
>>> pprint(data.items())
[('LE',
defaultdict(<type 'list'>, {'DEL-15': ['Failed'], 'DEL-14': ['Passed', 'Passed', 'Passed'], 'PRO-43': ['Failed'], 'PRO-45': ['Passed'], 'PRO-51': ['Passed'], 'GR-19': ['Passed', 'Passed'], 'GR-22': ['Passed'], 'GR-21': ['Failed'], 'GR-20': ['Passed']})),
('FT',
defaultdict(<type 'list'>, {'PRO-19': ['Passed'], 'PRO-20': ['Failed'], 'PRO-21': ['No Run'], 'PRO-16': ['Failed'], 'PRO-18': ['Passed', 'Passed'], 'GR-01': ['Passed'], 'GR-03': ['Passed'], 'GR-02': ['Passed', 'Passed', 'Passed']})),
('CD',
defaultdict(<type 'list'>, {'GR-07': ['Passed', 'Failed', 'Passed', 'Passed'], 'GR-09': ['Passed'], 'GR-13': ['No Run', 'No Run', 'No Run', 'Failed']}))]
В выводе, который вы показали, PRO-16 отображается как проход, пока он должен быть сбой, так как он имеет соответствующее значение Failed, а также в столбце C – user5253936
@ user5253936: извините, я не понял этих требований. Я обновил свой ответ - я думаю, что теперь он отвечает этим требованиям. – mhawke
@ user5253936: также обновлено, чтобы показать, как перебирать рамку данных pandas, возвращаемую 'read_csv()'. – mhawke