如何通过根据条件排除几列来计算所有行的平均值
How to calculate average of all rows by excluding a few columns based on a condition
我有一个棘手的数据清理要求,使用 pandas。我有一个只有二进制值的以下数据框。每行代表客户对调查问题的回答。下面的 df 有两个问题(q1 和 q2),他们的回答用“_”符号表示。例如,客户 aasww 提供 'a' 作为对 q1 的响应,并提供 'b' 作为对 q2 的响应。在某些情况下,客户可以跳过由 0 表示的问题(例如,客户 asdsd 跳过了 q1)
Customer_id
q1_a
q1_b
q1_0
q2_a
q2_b
q2_c
q2_0
asdsd
0
0
1
0
0
1
0
aasww
1
0
0
0
1
0
0
aaswe
0
1
0
0
0
0
1
aaswt
0
1
0
1
0
0
0
现在,我想通过排除具有“_0”的列来计算每列所有客户的平均值。但这里棘手的部分是,我只想计算回答了该特定问题的客户的平均值。例如,在上面的数据框中,客户 asdsd 跳过了 q1,因此在计算 Q1 的平均值时应该忽略该客户。这是预期的输出,
Customer_id
q1_a
q1_b
q2_a
q2_b
q2_c
asdsd
0
0
0
0
1
aasww
1
0
0
1
0
aaswe
0
1
0
0
0
aaswt
0
1
1
0
0
AVERAGE
33.3%
66.7%
33.3%
33.3%
33.3%
此外,我有 100 多个这样的专栏(调查中的问题太多)所以如果我们能有一个循环解决它的解决方案就太好了
这是使用 melt
的一种方法。这个想法是,我们过滤 DataFrame 的相关部分并 melt
它;然后过滤掉对一个问题的所有答案为 0 的客户(构建一个过滤器,将 all
转换为 groupby.transform
);然后对于剩余的客户,使用 groupby.mean
找到 mean
响应。最后,将这些方法分配回 out
DataFrame:
out = df.loc[:, ~df.columns.str.endswith('_0')].copy()
df1 = out.melt('Customer_id')
df1 = df1.join(df1.pop('variable').str.split('_', expand=True))
percentages = (df1.loc[~df1['value'].eq(0).groupby([df1['Customer_id'], df1[0]]).transform('all')]
.groupby([ 0, 1])['value'].mean() * 100)
percentages.index = percentages.index.map('_'.join)
out.loc[len(out)] = percentages
out.loc[len(out)-1, 'Customer_id'] = 'Average'
输出:
Customer_id q1_a q1_b q2_a q2_b q2_c
0 asdsd 0.000000 0.000000 0.000000 0.000000 1.000000
1 aasww 1.000000 0.000000 0.000000 1.000000 0.000000
2 aaswe 0.000000 1.000000 0.000000 0.000000 0.000000
3 aaswt 0.000000 1.000000 1.000000 0.000000 0.000000
4 Average 33.333333 66.666667 33.333333 33.333333 33.333333
- 获取回答每个问题的客户数量
- 将每列的总和除以回答的数字
#set customer_id as the index
df = df.set_index("Customer_id")
#filter columns that do not end with _0
answered = df.filter(regex="^(?!.*_0$)")
#map the column names to the number of customers that answered
counter = df.columns.str.split("_").str[0].map(answered.groupby(answered.columns.str.split("_").str[0],axis=1).sum().sum())
#compute averages
df.loc["Average"] = df.sum().div(counter)
#keep only answered columns in the output
output = df[answered.columns]
>>> df
q1_a q1_b q2_a q2_b q2_c
Customer_id
asdsd 0.000000 0.000000 0.000000 0.000000 1.000000
aasww 1.000000 0.000000 0.000000 1.000000 0.000000
aaswe 0.000000 1.000000 0.000000 0.000000 0.000000
aaswt 0.000000 1.000000 1.000000 0.000000 0.000000
Average 0.333333 0.666667 0.333333 0.333333 0.333333
我有一个棘手的数据清理要求,使用 pandas。我有一个只有二进制值的以下数据框。每行代表客户对调查问题的回答。下面的 df 有两个问题(q1 和 q2),他们的回答用“_”符号表示。例如,客户 aasww 提供 'a' 作为对 q1 的响应,并提供 'b' 作为对 q2 的响应。在某些情况下,客户可以跳过由 0 表示的问题(例如,客户 asdsd 跳过了 q1)
Customer_id | q1_a | q1_b | q1_0 | q2_a | q2_b | q2_c | q2_0 |
---|---|---|---|---|---|---|---|
asdsd | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
aasww | 1 | 0 | 0 | 0 | 1 | 0 | 0 |
aaswe | 0 | 1 | 0 | 0 | 0 | 0 | 1 |
aaswt | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
现在,我想通过排除具有“_0”的列来计算每列所有客户的平均值。但这里棘手的部分是,我只想计算回答了该特定问题的客户的平均值。例如,在上面的数据框中,客户 asdsd 跳过了 q1,因此在计算 Q1 的平均值时应该忽略该客户。这是预期的输出,
Customer_id | q1_a | q1_b | q2_a | q2_b | q2_c |
---|---|---|---|---|---|
asdsd | 0 | 0 | 0 | 0 | 1 |
aasww | 1 | 0 | 0 | 1 | 0 |
aaswe | 0 | 1 | 0 | 0 | 0 |
aaswt | 0 | 1 | 1 | 0 | 0 |
AVERAGE | 33.3% | 66.7% | 33.3% | 33.3% | 33.3% |
此外,我有 100 多个这样的专栏(调查中的问题太多)所以如果我们能有一个循环解决它的解决方案就太好了
这是使用 melt
的一种方法。这个想法是,我们过滤 DataFrame 的相关部分并 melt
它;然后过滤掉对一个问题的所有答案为 0 的客户(构建一个过滤器,将 all
转换为 groupby.transform
);然后对于剩余的客户,使用 groupby.mean
找到 mean
响应。最后,将这些方法分配回 out
DataFrame:
out = df.loc[:, ~df.columns.str.endswith('_0')].copy()
df1 = out.melt('Customer_id')
df1 = df1.join(df1.pop('variable').str.split('_', expand=True))
percentages = (df1.loc[~df1['value'].eq(0).groupby([df1['Customer_id'], df1[0]]).transform('all')]
.groupby([ 0, 1])['value'].mean() * 100)
percentages.index = percentages.index.map('_'.join)
out.loc[len(out)] = percentages
out.loc[len(out)-1, 'Customer_id'] = 'Average'
输出:
Customer_id q1_a q1_b q2_a q2_b q2_c
0 asdsd 0.000000 0.000000 0.000000 0.000000 1.000000
1 aasww 1.000000 0.000000 0.000000 1.000000 0.000000
2 aaswe 0.000000 1.000000 0.000000 0.000000 0.000000
3 aaswt 0.000000 1.000000 1.000000 0.000000 0.000000
4 Average 33.333333 66.666667 33.333333 33.333333 33.333333
- 获取回答每个问题的客户数量
- 将每列的总和除以回答的数字
#set customer_id as the index
df = df.set_index("Customer_id")
#filter columns that do not end with _0
answered = df.filter(regex="^(?!.*_0$)")
#map the column names to the number of customers that answered
counter = df.columns.str.split("_").str[0].map(answered.groupby(answered.columns.str.split("_").str[0],axis=1).sum().sum())
#compute averages
df.loc["Average"] = df.sum().div(counter)
#keep only answered columns in the output
output = df[answered.columns]
>>> df
q1_a q1_b q2_a q2_b q2_c
Customer_id
asdsd 0.000000 0.000000 0.000000 0.000000 1.000000
aasww 1.000000 0.000000 0.000000 1.000000 0.000000
aaswe 0.000000 1.000000 0.000000 0.000000 0.000000
aaswt 0.000000 1.000000 1.000000 0.000000 0.000000
Average 0.333333 0.666667 0.333333 0.333333 0.333333