# Preparing data
# Note that I have clean up the `jan` to `Jan` and `Charge` to `charge`
data = [{'Month': 'Jan', 'Name': 'Alice sal', 'id': 212, 'Info': 'charge', 'd/k': 'k', 'Ex/Im': 'export', 'Income': 100.15},
{'Month': 'Jan', 'Name': 'sal Alice', 'id': 212, 'Info': 'charge', 'd/k': 'k', 'Ex/Im': 'export', 'Income': 10},
{'Month': 'Jan', 'Name': 'Bob', 'id': 567, 'Info': 'charge', 'd/k': 'k', 'Ex/Im': 'export', 'Income': 200},
{'Month': 'Feb', 'Name': 'Alice sal', 'id': 212, 'Info': 'charge', 'd/k': 'k', 'Ex/Im': 'export', 'Income': 100},
{'Month': 'Jan', 'Name': 'Bob', 'id': 567, 'Info': 'cost', 'd/k': 'k', 'Ex/Im': 'import', 'Income': 75},
{'Month': 'Jan', 'Name': 'Bob', 'id': 567, 'Info': 'charge', 'd/k': 'D', 'Ex/Im': 'export', 'Income': 50}]
df = pd.DataFrame(data)
# Clean up name by ID
# Create a dataframe to store names depends on whichever found first.
df_name = df.groupby('id').first()[['Name']]
def cleanup_name(row, df_name):
return df_name.at[row['id'], 'Name']
# `apply` is useful in applying complex logic, but it comes with some performance cost.
df['Name'] = df.apply(lambda x: cleanup_name(x, df_name), axis=1)
# 1. Negate the values of `Income` when `D` is found,
# you can write your own method and use `df.apply`
# to make it idempotent if you prefer.
df.loc[df['d/k'] == 'D', 'Income'] = -df[df['d/k'] == 'D']['Income']
# 2. Group by
gdf = df.groupby(['id', 'Month', 'Ex/Im', 'Info']).agg({'Income':'sum', 'Name':'first'})
# 3. Lastly apply `pivot_table` which is quite similar to what you have wrote.
gdf.pivot_table(
index=["id", "Name"],
columns=["Month", "Ex/Im", "Info"],
values=["Name", "Income"],
aggfunc='sum',
fill_value=0)
# Result:
# Income
# Month Feb Jan
# Ex/Im export export import
# Info charge charge cost
# id Name
# 212 Alice sal 100 110 0
# 567 Bob 0 150 75
Но сначала нужно очистить данные, есть один jan
в Month
, где остальные начинаются с заглавной буквы. То же самое для Info
, начинаются с заглавной буквы.
Обновление:
После очистки имени все написанное до этого работает хорошо для меня, по данным ниже:
data = [
{'Month': 'Jan', 'Name': 'Alice sal', 'id': 212, 'Info': 'charge', 'd/k': 'K', 'Ex/Im': 'export', 'Income': 100},
{'Month': 'Jan', 'Name': 'Alice sal', 'id': 212, 'Info': 'charge', 'd/k': 'K', 'Ex/Im': 'export', 'Income': 10},
{'Month': 'Jan', 'Name': 'Alice sal', 'id': 212, 'Info': 'charge', 'd/k': 'D', 'Ex/Im': 'export', 'Income': 100},
{'Month': 'Jan', 'Name': 'Alice sal', 'id': 212, 'Info': 'charge', 'd/k': 'D', 'Ex/Im': 'export', 'Income': 100},
{'Month': 'Jan', 'Name': 'Alice sal', 'id': 212, 'Info': 'cost', 'd/k': 'K', 'Ex/Im': 'export', 'Income': 200},
{'Month': 'Jan', 'Name': 'Alice sal', 'id': 212, 'Info': 'cost', 'd/k': 'D', 'Ex/Im': 'export', 'Income': 10},
{'Month': 'Jan', 'Name': 'Alice sal', 'id': 212, 'Info': 'cost', 'd/k': 'D', 'Ex/Im': 'export', 'Income': 20},
{'Month': 'Feb', 'Name': 'Alice sal', 'id': 212, 'Info': 'charge', 'd/k': 'K', 'Ex/Im': 'export', 'Income': 100}]
df = pd.DataFrame(data)
Было бы здорово, если вы подготовите этот код для генерации данных в следующий раз, когда вы зададите вопрос, это сократит время, чтобы получить правильный ответ =)