gpt4 book ai didi

python - Pandas 中的数据透视表/反转表(但不完全是)

转载 作者:太空狗 更新时间:2023-10-30 02:35:54 27 4
gpt4 key购买 nike

我有一个问题,为此我设法编写了一些工作代码,但我想看看这里是否有人可以提供更简单/更有条理/不那么丑陋/更内置的解决方案。抱歉,标题非常模糊,但我无法用一句话概括这个问题。

问题

基本上我有一个如下所示的 DataFrame:

  id  foo_col  A  B  C  D
0 x nothing 2 0 1 1
1 y to 0 0 3 2
2 z see 1 3 2 2

现在我想将列 ['A', 'B', 'C', 'D'] 转换为 ['W1', 'W2', ' W3'],这将是前 3 列名称(每行)使用每行中的数字排序。

这样,id为x的行将有A(2),C(1), D (with 1), B (with 0), 从而得到'W1' = 'A', 'W2' = 'C' , 'W3' = 'D'

目标 DataFrame 将如下所示:

  id  foo_col W1 W2    W3
0 x nothing A C D
1 y to C D None
2 z see B C D

规则

  1. 可以使用字母顺序(行 x)打破平局;
  2. 如果少于 3 个非零 W,缺少的将得到 None(行 y);
  3. 如果有超过 3 个非零 W,多出的一个将不会进入最终的 DataFrame(行 z)。

解决方案

import pandas as pd
import operator
import more_itertools as mit

# Define starting DataFrame
df = pd.DataFrame(data={'id': ['x', 'y', 'z'],
'foo_col': ['nothing', 'to', 'see'],
'A': [2, 0, 1],
'B': [0, 0, 3],
'C': [1, 3, 2],
'D': [1, 2, 2]})

print('Original DataFrame')
print(df.to_string())
print()

# Define 'source' and 'target' columns
w_columns = ['A', 'B', 'C', 'D']
w_labels = ['W1', 'W2', 'W3']

# Define function to do this pivoting
def pivot_w(row, columns=w_columns, labels=w_labels):
# Convert relevant columns of DF to dictionary
row_dict = row[columns].to_dict()
# Convert dictionary to list of tuples
row_tuples = [tuple(d) for d in row_dict.items()]
# Sort list of tuples based on the second item (the value in the cell)
row_tuples.sort(key=operator.itemgetter(1), reverse=True)
# Get the sorted 'column' labels
row_list = [x[0] for x in row_tuples if x[1] != 0]
# Enforce rules 2 and 3
if len(row_list) < 3:
row_list = list(mit.take(3, mit.padnone(row_list)))
else:
row_list = row_list[:3]

# Create a dictionary using the W lables
output = {i: j for i, j in zip(labels, row_list)}

return output

# Get DataFrame with W columns and index
df_w = pd.DataFrame(list(df.apply(pivot_w, axis=1)))
# Merge DataFrames on index
df = df.merge(df_w, how='inner', left_index=True, right_index=True)
# Drop A, B, C, D columns
df.drop(columns=w_columns, inplace=True)

print('Final DataFrame')
print(df.to_string())

除了可能重复使用同一个变量来存储函数中的中间结果之外,还有什么我可以做的更聪明的事情吗?

P.S. 如果你们中的任何人有关于更好/更清晰的标题的想法,请随时进行编辑!

最佳答案

您可以使用 argsort用于获取前 3 列名称,但随后有必要用排序和 np.where 替换 0 值中的位置:

w_columns = ['A', 'B', 'C', 'D']
w_labels = ['W1', 'W2', 'W3']

#sorting columns names by values, last are 0 values (because minimal)
arr = np.array(w_columns)[np.argsort(-a, axis=1)]
print (arr)
[['A' 'C' 'D' 'B']
['C' 'D' 'A' 'B']
['B' 'C' 'D' 'A']]

#sorting values for 0 to last positions and compare by 0
mask = -np.sort(-df[w_columns], axis=1) == 0
print (mask)
[[False False False True]
[False False True True]
[False False False False]]

#replace first 3 'columns' by mask to None
out = np.where(mask[:, :3], None, arr[:, :3])
print (out)
[['A' 'C' 'D']
['C' 'D' None]
['B' 'C' 'D']]

df1 = pd.DataFrame(out, columns=w_labels, index=df.index)
print (df1)
W1 W2 W3
0 A C D
1 C D None
2 B C D

df = df.drop(w_columns, 1).join(df1)
print (df)
id foo_col W1 W2 W3
0 x nothing A C D
1 y to C D None
2 z see B C D

如果可能需要排除一些在所有选择值中都不是最小值的其他值,则可以将其替换为 NaN 并用于测试使用 np.isnan:

a = np.where(df[w_columns] != 0, df[w_columns], np.nan)
print (a)
[[ 2. nan 1. 1.]
[nan nan 3. 2.]
[ 1. 3. 2. 2.]]

arr = np.array(w_columns)[np.argsort(-a, axis=1)]
mask = np.isnan(np.sort(a, axis=1))

out = np.where(mask[:, :3], None, arr[:, :3])
print (out)

[['A' 'C' 'D']
['C' 'D' None]
['B' 'C' 'D']]

关于python - Pandas 中的数据透视表/反转表(但不完全是),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57524881/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com