Python按多列分组,创建字符串列表,但对数字求和
目前,我的数据帧看起来类似于:Python按多列分组,创建字符串列表,但对数字求和,python,pandas,pandas-groupby,Python,Pandas,Pandas Groupby,目前,我的数据帧看起来类似于: ID Year Str1 Str2 Value 0 1 2014 high black 120 1 1 2015 high blue 20 2 2 2014 medium red 10 3 2 2014 medium blue 50 4 3 2015 low blue 30 5 3
ID Year Str1 Str2 Value
0 1 2014 high black 120
1 1 2015 high blue 20
2 2 2014 medium red 10
3 2 2014 medium blue 50
4 3 2015 low blue 30
5 3 2015 high blue .5
6 3 2015 high red 10
期望的:
ID Year Str1 Str2 Value
0 1 2014 high black 120
1 1 2015 high blue 20
2 2 2014 medium red, blue 60
3 3 2015 low, high blue, red 40.5
尝试按列ID和列名称分组,然后获取数字的总和,但得到一个字符串列表。如果可以像示例中那样删除重复的字符串,这将很有帮助,但不是必需的
此操作将对大约100个数据帧执行,ID和Year是每个数据帧中唯一可以找到的列名。数据帧确实略有不同:它们有value列、str列或两者兼有
我浏览了很多stackoverflow并尝试:
df.groupby(['ID', 'Year'], as_index=False).agg(lambda x: x.sum() if x.dtype=='int64' else ', '.join(x))
导致错误的DataFrame对象没有属性dtype(这很有意义,因为按多列分组会返回更多的数据帧)
我还试着一列一列地循环,如果列中有数字,它会计算总数,否则会列出一个列表:
for col in df:
if col in ['ID', 'Year']:
continue
if df[col].dtype.kind == 'i' or df[col].dtype.kind == 'f':
df = df.groupby(['ID', 'Year'])[col].apply(sum)
else:
df = df.groupby(['ID', 'Year'])[col].unique().reset_index()
但是,在第一次执行该操作后,它去掉了所有其他列
提前感谢。您需要检查
数值列是否为列,例如:
我有一个类似的问题,所以假设我有一个这样的数据列,我想通过电子邮件分组,并对不同的列执行不同的agg函数,所以标准的groupby函数不够好
无论如何,这里有一个虚拟数据集:
Email Phone State
0 email@gmail.com 123-456-7890 NY
1 email@gmail.com 321-654-0987 LA
2 person@gmail.com 123-789-4567 WA
3 dummy@gmail.com 873-345-3456 MN
4 dummy@gmail.com 123-345-3456 NY
5 email@gmail.com 000-000-0000 KY
知道哪一个是第一个被复制的项目会很有用,所以我们会处理它,而忽略其他项目。首先,我要标记第一个重复项
这看起来很复杂,但它所做的是:获取所有复制的真实VAL列表
,并对所有第一个复制的真实VAL列表执行and操作。
df["first_dupe"] = df.duplicated("Email", keep=False) & ~df.duplicated("Email", keep="first")
然后将此函数应用于数据帧:
def combine_rows(row, key="Email", cols_to_combine=["Phone", "State"]):
"""takes in a row, looks at the key column
if its the first dupe, combines the data in cols_to_combine with the other rows with same key
needs a dataframe with a bool column first_dupe with True if the row is the first dupe"""
if row["first_dupe"] == True:
# making a df of dupes item
dupes = df[df[key]==row[key]]
for i, dupe_row in dupes.iloc[1:].iterrows(): # skipping the first row, since thats our first_dupe
for col in cols_to_combine:
row[col] += ", " + dupe_row[col]
# make sure first_dupe doesn't get processed again
row.first_dupe = False
return row
df = df.apply(combine_rows, axis=1, result_type=None)
您可以修改combine rows函数,对不同的列执行不同的操作。如果有人遇到奇怪的行为,而不是获得正确的列表/总和,您会得到每行的列名列表,数据中可能有NaN值。将NaN值替换为df=df。需要使用fillna(“”)
才能工作。
df["first_dupe"] = df.duplicated("Email", keep=False) & ~df.duplicated("Email", keep="first")
def combine_rows(row, key="Email", cols_to_combine=["Phone", "State"]):
"""takes in a row, looks at the key column
if its the first dupe, combines the data in cols_to_combine with the other rows with same key
needs a dataframe with a bool column first_dupe with True if the row is the first dupe"""
if row["first_dupe"] == True:
# making a df of dupes item
dupes = df[df[key]==row[key]]
for i, dupe_row in dupes.iloc[1:].iterrows(): # skipping the first row, since thats our first_dupe
for col in cols_to_combine:
row[col] += ", " + dupe_row[col]
# make sure first_dupe doesn't get processed again
row.first_dupe = False
return row
df = df.apply(combine_rows, axis=1, result_type=None)