Python 没有 PANDAS 的聚合
Python Aggregation without PANDAS
我有一个排序的嵌套列表。列表中的每个元素都有 3 个子元素; 'Drugname'、Doctor_id、金额。对于给定的药物名称(重复),医生 ID 不同,数量也不同。请参阅下面的示例列表..
我需要一个输出,对于每个药物名称,我需要计算唯一医生 ID 总数和该药物的美元金额总和。例如,对于下面的列表片段..
[
['CIPROFLOXACIN HCL', 1801093968, 61.49],
['CIPROFLOXACIN HCL', 1588763981, 445.23],
['HYDROCODONE-ACETAMINOPHEN', 1801093968, 251.52],
['HYDROCODONE-ACETAMINOPHEN', 1588763981, 263.16],
['HYDROXYZINE HCL', 1952310666, 945.5],
['IBUPROFEN', 1801093968, 67.06],
['INVEGA SUSTENNA', 1952310666, 75345.68]
]
期望的输出如下。
[
['CIPROFLOXACIN HCL', 2, 516.72],
['HYDROCODONE-ACETAMINOPHEN', 2, 514.68]
['HYDROXYZINE HCL', 1, 945.5]
['IBUPROFEN', 1, 67.06]
['INVEGA SUSTENNA', 1, 75345.68]
]
在数据库世界中,这是最简单的事情,只需对药物名称进行简单的 GROUP BY。在 Python 中,我不允许使用 PANDAS、NumPy 等。只是 Python 的基本构建块。我尝试了下面的代码,但我无法重置计数变量来计算医生 ID 和数量。此注释代码是几次尝试之一。不确定我是否需要使用嵌套 for 循环或 for 循环-while 循环组合。
感谢所有帮助!
aggr_list = []
temp_drug_name = ''
doc_count = 0
amount = 0
for list_element in sorted_new_list:
temp_drug_name = list_element[0]
if temp_drug_name == list_element[0]:
amount += float(amount)
doc_count += 1
aggr_list.append([temp_drug_name, doc_count, amount])
print(aggr_list)
由于列表已经排序,您可以简单地遍历列表(在下面的示例中命名为 l
)并跟踪最后一次迭代的名称,如果当前迭代的名称是与上一个不同,在输出中插入一个新条目。使用一个集合来跟踪当前药物已经看到的医生 ID,如果没有看到医生 ID,则只将输出的最后一个条目的第二项增加 1。并将输出的最后一个条目的第三项增加当前迭代的数量:
output = []
last = None
for name, id, amount in l:
if name != last:
output.append([name, 0, 0])
last = name
ids = set()
if id not in ids:
output[-1][1] += 1
ids.add(id)
output[-1][2] += amount
output
变为:
[['CIPROFLOXACIN HCL', 2, 506.72],
['HYDROCODONE-ACETAMINOPHEN', 2, 514.6800000000001],
['HYDROXYZINE HCL', 1, 945.5],
['IBUPROFEN', 1, 67.06],
['INVEGA SUSTENNA', 1, 75345.68]]
请注意,十进制浮点数在计算机使用的二进制系统中是近似值(请阅读Is floating point math broken?),因此如上面第二项的总和所示,一些小错误是不可避免的。
这是一个注重可读性的解决方案,它没有考虑到您原始列表中的条目是按药物名称排序的。
它首先传递所有数据条目,然后传递唯一药物的数量。
要仅对已排序数据的所有条目执行一次传递,请参阅@blhsing 解决方案
from collections import defaultdict, namedtuple
Entry = namedtuple('Entry',['doctors', 'prices'])
processed_data = defaultdict(lambda: Entry(doctors=set(), prices=[]))
for entry in data:
drug_name, doctor_id, price = entry
processed_data[drug_name].doctors.add(doctor_id)
processed_data[drug_name].prices.append(price)
stat_list = [[drug_name, len(entry.doctors), sum(entry.prices)] for drug_name, entry in processed_data.items()]
没有 Pandas 或 defaultdict:
d={}
for row in l:
if row[0] in d:
d[row[0]].append(row[1])
d[row[0]].append(row[2])
else:
d[row[0]]=[row[1]]
d[row[0]].append(row[2])
return [[key, len(set(val[0::2])), sum(val[1::2])] for key, val in d.items()]
可重复使用的解决方案,适用于那些通过 Google:
到达这里的人
def group_by(rows, key):
m = {}
for row in rows:
k = key(row)
try:
m[k].append(row)
except KeyError:
m[k] = [row]
return m.values()
grouped_by_drug = group_by(data, key=lambda row: row[0])
result = [
(
drug_rows[0][0],
len(drug_rows),
sum(row[2] for row in drug_rows)
)
for drug_rows in grouped_by_drug
]
您也可以在此实现中使用 defaultdict
,对于我的用例来说,这稍微快一些。
我有一个排序的嵌套列表。列表中的每个元素都有 3 个子元素; 'Drugname'、Doctor_id、金额。对于给定的药物名称(重复),医生 ID 不同,数量也不同。请参阅下面的示例列表..
我需要一个输出,对于每个药物名称,我需要计算唯一医生 ID 总数和该药物的美元金额总和。例如,对于下面的列表片段..
[
['CIPROFLOXACIN HCL', 1801093968, 61.49],
['CIPROFLOXACIN HCL', 1588763981, 445.23],
['HYDROCODONE-ACETAMINOPHEN', 1801093968, 251.52],
['HYDROCODONE-ACETAMINOPHEN', 1588763981, 263.16],
['HYDROXYZINE HCL', 1952310666, 945.5],
['IBUPROFEN', 1801093968, 67.06],
['INVEGA SUSTENNA', 1952310666, 75345.68]
]
期望的输出如下。
[
['CIPROFLOXACIN HCL', 2, 516.72],
['HYDROCODONE-ACETAMINOPHEN', 2, 514.68]
['HYDROXYZINE HCL', 1, 945.5]
['IBUPROFEN', 1, 67.06]
['INVEGA SUSTENNA', 1, 75345.68]
]
在数据库世界中,这是最简单的事情,只需对药物名称进行简单的 GROUP BY。在 Python 中,我不允许使用 PANDAS、NumPy 等。只是 Python 的基本构建块。我尝试了下面的代码,但我无法重置计数变量来计算医生 ID 和数量。此注释代码是几次尝试之一。不确定我是否需要使用嵌套 for 循环或 for 循环-while 循环组合。
感谢所有帮助!
aggr_list = []
temp_drug_name = ''
doc_count = 0
amount = 0
for list_element in sorted_new_list:
temp_drug_name = list_element[0]
if temp_drug_name == list_element[0]:
amount += float(amount)
doc_count += 1
aggr_list.append([temp_drug_name, doc_count, amount])
print(aggr_list)
由于列表已经排序,您可以简单地遍历列表(在下面的示例中命名为 l
)并跟踪最后一次迭代的名称,如果当前迭代的名称是与上一个不同,在输出中插入一个新条目。使用一个集合来跟踪当前药物已经看到的医生 ID,如果没有看到医生 ID,则只将输出的最后一个条目的第二项增加 1。并将输出的最后一个条目的第三项增加当前迭代的数量:
output = []
last = None
for name, id, amount in l:
if name != last:
output.append([name, 0, 0])
last = name
ids = set()
if id not in ids:
output[-1][1] += 1
ids.add(id)
output[-1][2] += amount
output
变为:
[['CIPROFLOXACIN HCL', 2, 506.72],
['HYDROCODONE-ACETAMINOPHEN', 2, 514.6800000000001],
['HYDROXYZINE HCL', 1, 945.5],
['IBUPROFEN', 1, 67.06],
['INVEGA SUSTENNA', 1, 75345.68]]
请注意,十进制浮点数在计算机使用的二进制系统中是近似值(请阅读Is floating point math broken?),因此如上面第二项的总和所示,一些小错误是不可避免的。
这是一个注重可读性的解决方案,它没有考虑到您原始列表中的条目是按药物名称排序的。
它首先传递所有数据条目,然后传递唯一药物的数量。
要仅对已排序数据的所有条目执行一次传递,请参阅@blhsing 解决方案
from collections import defaultdict, namedtuple
Entry = namedtuple('Entry',['doctors', 'prices'])
processed_data = defaultdict(lambda: Entry(doctors=set(), prices=[]))
for entry in data:
drug_name, doctor_id, price = entry
processed_data[drug_name].doctors.add(doctor_id)
processed_data[drug_name].prices.append(price)
stat_list = [[drug_name, len(entry.doctors), sum(entry.prices)] for drug_name, entry in processed_data.items()]
没有 Pandas 或 defaultdict:
d={}
for row in l:
if row[0] in d:
d[row[0]].append(row[1])
d[row[0]].append(row[2])
else:
d[row[0]]=[row[1]]
d[row[0]].append(row[2])
return [[key, len(set(val[0::2])), sum(val[1::2])] for key, val in d.items()]
可重复使用的解决方案,适用于那些通过 Google:
到达这里的人def group_by(rows, key):
m = {}
for row in rows:
k = key(row)
try:
m[k].append(row)
except KeyError:
m[k] = [row]
return m.values()
grouped_by_drug = group_by(data, key=lambda row: row[0])
result = [
(
drug_rows[0][0],
len(drug_rows),
sum(row[2] for row in drug_rows)
)
for drug_rows in grouped_by_drug
]
您也可以在此实现中使用 defaultdict
,对于我的用例来说,这稍微快一些。