首页 > 解决方案 > 通过创建具有唯一键的新数据帧,将非范式数据帧转换为 1NF

问题描述

我不太清楚如何提出这个问题,欢迎提出改进标题的建议。

让我们从我的巨大桌子开始,其中有多个不属于任何正常形式的道具。我用多种语言特定的数据集创建了这个表。

+-----+---------+--------+-----+----------+
| Key | Prop_A  | Prob_B | ... | Language |
+-----+---------+--------+-----+----------+
|   1 | Light   | Stone  |     | EN       |
|   2 | Medium  | Wood   |     | EN       |
|   1 | Leicht  | Stein  |     | DE       |
|   3 | Hard    | Stone  |     | EN       |
|   2 | Mittel  | Holz   |     | DE       |

我会压缩它们并在单独的数据帧中提取冗余信息。所以结果应该是这样的:

Example: with NF
+-----+---------+--------+
| Key | Prop_A  | Prob_B |
+-----+---------+--------+
|   1 | LIGHT   | STONE  |
|   2 | MEDIUM  | WOOD   |
|   3 | HARD    | STONE  |
+-----+---------+--------+

大写的值代表离散值的属性表的主键

Example: Prop_A Table
+--------+---------+--------+
|  Key   |   EN    |   DE   |
+--------+---------+--------+
| LIGHT  | Light   | Leicht |
| MEDIUM | Medium  | Mittel |
| HARD   | Hard    | Hart   |
|        |         |        |
+--------+---------+--------+

我的第一个想法是分组KeyLanguage然后将属性(Prob_A,Prob_B)应用于字典。我试过了groupby('key')[['Prob_A', 'Language']].apply(lambda x: x.values.tolist()).to_dict()。但是我总是失败,因为我从来没有得到靠近我上面桌子的东西。

第二个想法是按两个步骤分组。首先按键分组,然后按语言和属性本身分组。收集列表中的结果。最后一个想法是按键和语言分组并遍历所有行。在循环中,值应该收集在一个集合中,每个属性也包含语言信息。但是我不知道集合的结构应该是什么样子,结果看起来像上面那样。

还阅读了 pandas 文档中关于多索引和分类的一些章节,但它不适合我的用例。在过去,我更多地使用 pandas 来聚合数值而不是数据转换。

我觉得我为我的问题使用了错误的工具(熊猫)。在我的脑海中,这个想法很清楚,但我看不到 pandas 的解决方案。你能给我一些想法如何用熊猫或其他建议解决这个问题吗?

我的演示 DF 看起来像

lst = [["1",'Light', "Stone", "EN"],["2",'Medium', "Wood", "EN"], ["1",'Leicht', "Stein", "DE"],["3",'Hard', "Stone", "EN"],["2",'Mittel', "Holz", "DE"]]
df = pd.DataFrame(lst,columns= ['Key','Prop_A', 'Prob_B','Language'])
columns = ['Prop_A', 'Prob_B']

标签: pythonpandasalgorithm

解决方案


创建一个dictionary其中 eachkey是列,内容是每列的属性表,然后只需修改原始数据框。由于字典是根据原始字典创建的,因此不会丢失任何键:

columns = ['Prop_A', 'Prob_B']

dfs = {
    col:
    df[['Key', col, 'Language']].pivot(
        columns='Language', values=col, index='Key')
    for col in columns
}

dfs['Prop_A']

#         DE      EN
# Key       
# LIGHT   LEICHT  LIGHT
# MEDIUM  MITTEL  MEDIUM
# HARD    NaN     HARD

df_f = df.query('Language == "EN"')[['Key'] + columns].\
    apply(lambda x: x.str.upper() if x.name in columns else x).\
    drop_duplicates()

df_f

#   Key Prop_A  Prob_B
# 0 1   LIGHT   STONE
# 1 2   MEDIUM  WOOD
# 3 3   HARD    STONE

示例中没有HartinProp_A


推荐阅读