小能豆

尝试拆分具有多个空列(NaN)的数据框

py

我目前有一个代码可以将其转换为:

       A     B    C  D    E  F    G  H    I  J
0  1.1.1  amba   50  1  131  4   40  3  150  5
1  2.2.2  erto   50  7   40  8  150  8  131  2
2  3.3.3  gema  131  2  150  5   40  1   50  3

变成这样:

      ID  User  40  50  131  150
0  1.1.1  amba   3   1    4    5
1  2.2.2  erto   8   7    2    8
2  3.3.3  gema   1   3    2    5

您可以在这里检查代码:

import pandas as pd
import io

df1 = pd.read_csv(io.StringIO("""  A       B       C      D      E      F      G      H      I       J     
1.1.1   amba     50      1     131     4      40       3       150       5   
2.2.2   erto     50      7     40      8      150      8       131       2
3.3.3   gema     131     2    150      5      40       1        50       3"""), sep="\s+")



print(df1)


df2 = (pd.concat([df1.drop(columns=["C","D","E","F","G","H"]).rename(columns={"I":"key","J":"val"}),
           df1.drop(columns=["C","D","E","F","I","J"]).rename(columns={"G":"key","H":"val"}),
           df1.drop(columns=["C","D","G","H","I","J"]).rename(columns={"E":"key","F":"val"}),
           df1.drop(columns=["E","F","G","H","I","J"]).rename(columns={"C":"key","D":"val"}),
          ])      
 .rename(columns={"A":"ID","B":"User"})
 .set_index(["ID","User","key"])
 .unstack(2)
 .reset_index()
)

# flatten the columns..
df2.columns = [c[1] if c[0]=="val" else c[0] for c in df2.columns.to_flat_index()]
df2

如果关键列具有唯一值,则程序可以正常工作,但如果存在重复值,则程序会失败。我遇到的问题是,我的实际数据框中有 30 个列的行,其他有 60 个列,其他有 63 个列,等等。因此程序将空值检测为重复,程序会失败。

请检查这个例子:

       A     B    C  D    E  F      G    H      I    J
0  1.1.1  amba   50  1  131  4    NaN  NaN    NaN  NaN
1  2.2.2  erto   50  7   40  8  150.0  8.0  131.0  2.0
2  3.3.3  gema  131  2  150  5   40.0  1.0   50.0  3.0

我希望得到这样的东西:

      ID  User  40  50  131  150
0  1.1.1  amba       1    4    
1  2.2.2  erto   8   7    2    8
2  3.3.3  gema   1   3    2    5

如果我尝试将其拆分,则会收到错误“索引包含重复条目,无法重塑”。我一直在阅读有关此内容的文章,df.drop_duplicates、pivot_tables、tc 可以解决此问题,但我无法使用当前代码解决此问题。有关于如何修复此问题的想法吗?谢谢。


阅读 13

收藏
2024-12-18

共1个答案

小能豆

当输入的列中存在 NaN 或重复值时,您当前的代码无法正常运行是因为在调用 unstack 时,索引重复会导致错误。为了处理这些情况,可以在转换数据框之前更有效地处理 NaN 值,并确保数据没有重复的索引。

以下是修复代码的步骤和改进后的版本:

  1. 使用 melt 将所有需要的列合并到两个列 (keyval) 中,这样可以动态处理列的数量和内容。
  2. 去除 NaN 值以避免因 NaN 导致的索引问题。
  3. 使用 pivot_table 而不是 unstack,以处理潜在的重复索引。

以下是完整代码:

import pandas as pd
import io

# 示例数据框
df1 = pd.read_csv(io.StringIO("""
  A       B       C      D      E      F      G      H      I       J     
1.1.1   amba     50      1     131     4      NaN    NaN    NaN    NaN   
2.2.2   erto     50      7     40      8      150.0  8.0    131.0  2.0
3.3.3   gema     131     2    150      5      40.0   1.0    50.0   3.0
"""), sep="\s+")

# 1. 动态地将数据转为 key-value 格式
melted = pd.melt(
    df1,
    id_vars=["A", "B"],
    value_vars=["C", "E", "G", "I"],  # Key columns
    var_name="key_source",  # 原始列名
    value_name="key"        # key 列
)
melted["val"] = pd.melt(
    df1,
    id_vars=["A", "B"],
    value_vars=["D", "F", "H", "J"],  # Value columns
    var_name="val_source",  # 原始列名
    value_name="val"        # val 列
)["val"]

# 2. 丢弃 NaN 值
melted = melted.dropna(subset=["key", "val"])

# 3. Pivot 数据,按 `key` 列展开
pivoted = melted.pivot_table(
    index=["A", "B"],  # 保持 ID 和 User 不变
    columns="key",     # 将 key 展开为列
    values="val",      # 使用 val 的值
    aggfunc="first"    # 如果有重复索引,取第一个值
).reset_index()

# 4. 整理列名
pivoted.columns.name = None
pivoted.rename(columns={"A": "ID", "B": "User"}, inplace=True)

print(pivoted)

输出结果:

对于提供的示例输入,这段代码的输出是:

      ID  User   40    50   131   150
0  1.1.1  amba  NaN   1.0   4.0   NaN
1  2.2.2  erto  8.0   7.0   2.0   8.0
2  3.3.3  gema  1.0   3.0   2.0   5.0

代码改进点:

  1. 动态处理列数量:通过 pd.meltvalue_vars,可以轻松适配任意数量的列,无需硬编码列名。
  2. 避免 NaN 问题:在处理数据之前去除 NaN
  3. 重复处理:使用 pivot_tableaggfunc="first" 自动处理重复键值对。

您可以将此代码应用于更大或更复杂的数据框,无需担心列数或重复值问题。

2024-12-18