Pandas DataFrame - 将同一索引下的一个列的值合并为列表

15

我一直在尝试解决这个问题,但一直未能成功。这几乎是与此处至少有一个其他问题重复的,但我无法从相关的在线答案中完全弄清楚我要找的东西。

我有一个Pandas DataFrame(我们称之为df),看起来像是这样:

Name    Value        Value2
'A'     '8.8.8.8'    'x'
'B'     '6.6.6.6'    'y'
'A'     '6.6.6.6'    'x'
'A'     '8.8.8.8'    'x'

其中Name是索引。我希望将其转换为类似于以下的形式:

Name    Value                     Value2
'A'     ['8.8.8.8', '6.6.6.6']    'x'
'B'     ['6.6.6.6']               'y'

因此,基本上,与相同索引对应的每个Value应该合并为一个列表(或集合、元组),并将该列表作为相应索引的Value。并且,如所示,Value2 在类似索引的行之间是相同的,因此最终应该保持不变。

我成功地做到的一切就是弄清楚如何将Value列中的每个元素变成列表:

df['Value'] = pd.Series([[val] for val in df['Value']])

在我在本帖开头链接的问题中,合并具有重复索引的列的推荐方法是使用df.groupby(df.index).sum()。 我知道我需要除df.index之外的其他内容作为groupby的参数,因为Value列被视为特殊情况,而我不确定应该放什么来代替sum(),因为那不是我正在寻找的。

希望我正在寻找的内容很清楚,请告诉我是否有什么可以详细说明的地方。 我还尝试简单地遍历DataFrame,查找具有相同索引的行,将Values组合成列表并相应地更新df。在尝试一段时间后,我想找一个更像Pandas方式处理此问题的方法。


编辑:作为对dermen答案的跟进,那个解决方案有些可行。 Values似乎确实正确地连接成了一个列表。 我意识到的一件事是,unique函数返回一个Series,而不是DataFrame。 此外,实际设置中除NameValueValue2之外还有更多列。 但我认为我成功地解决了这两个问题,具体如下:

gb = df.groupby(tuple(df.columns.difference(['Value'])))
result = pd.DataFrame(gb['Value'].unique(), columns=df.columns)

第一行将除了 Value 列以外的列作为参数传递给 groupby,第二行将 unique 返回的 Series 转换为一个与 df 相同列的 DataFrame

但我认为除此之外(除非有人发现问题),几乎所有的功能都能按预期工作。然而,似乎这里有些地方有点不对劲。当我尝试使用 to_csv 将其输出到文件时,顶部有重复的表头(但只有某些表头被重复了,据我所知没有真正的模式)。此外,Value 列的列表被截断了,这可能是一个更简单的问题需要修复。当前的 csv 输出如下:

Name    Value                   Value2    Name    Value2
'A'     ['8.8.8.8' '7.7.7.7'    'x'                     
'B'     ['6.6.6.6']             'y'

上面的内容看起来很奇怪,但这正是输出中的样子。请注意,与本帖开头所提供的示例相反,假设有超过2个AValues(以便我可以说明这一点)。当我使用实际数据进行操作时,Value列表在前4个元素之后被截断。


A 不应该有三个值吗? - Padraic Cunningham
在最终的配置中?不完全是,我不想在索引列表中包含重复的“Values”(这就是为什么我认为我可能想要使用Sets)。 - grish
1
df.drop_duplicates("Value",inplace=True) 会删除重复的数据。 - Padraic Cunningham
@PadraicCunningham 是的,但在这种设置中使用它存在问题。有时,“B”的“Value”将与“A”的“Value”相同,即使每个“Value”都相同,我也想保留它们,因为它们具有不同的索引。编辑:但我认为 df.drop_duplicates(["Name", "Value"]) 可以解决重复的问题。 - grish
1个回答

16

我认为您想要使用pandas.Series.unique。首先,将'Name'索引变成一列。

df
#     Value2  Value
#Name              
#A         x    8.8
#B         y    6.6
#A         x    6.6
#A         x    8.8

df.reset_index(inplace=True)
#  Name Value2  Value
#0    A      x    8.8
#1    B      y    6.6
#2    A      x    6.6
#3    A      x    8.8

接下来调用groupby函数,并在'Value'系列上调用unique函数。

gb = df.groupby(['Name','Value2'])
result = gb['Value'].unique()
result.reset_index(inplace=True) #lastly, reset the index
#  Name Value2       Value
#0    A      x  [8.8, 6.6]
#1    B      y       [6.6]

最后,如果你想再次将'Name'作为索引,请执行以下操作:

result.set_index( 'Name', inplace=True)
#     Value2       Value
#Name                   
#A         x  [8.8, 6.6]
#B         y       [6.6]

更新

作为跟进,确保在重置索引后重新分配结果。

result = gb['Value'].unique()
type(result)
#pandas.core.series.Series

result = result.reset_index()
type(result)
#pandas.core.frame.DataFrame

保存为CSV(而非TSV)

在这里不建议使用CSV,因为“值”列中有逗号。相反,建议保存为TSV,您仍然可以使用相同的方法to_csv,只需更改sep参数:

result.to_csv( 'result.txt', sep='\t')

如果我将result.txt作为TSV在EXCEL中加载,我会得到以下结果: enter image description here

谢谢你的回答dermen,我已经根据你的建议更新了原帖。 - grish
1
再次感谢回复!一切运行良好,必须喜欢Pandas和SO社区。 - grish
很高兴它能够正常工作,是的,我非常喜欢Pandas和Stack Overflow! - dermen
你能同时对多列进行操作吗?比如在数据框中,将表格中的值2也转换成列表。 - Lost1
我在使用 groupby 方法访问多列时,出现了 KeyError 错误。有什么建议吗? - Murtaza Haji
@MurtazaHaji,你可以在当前版本的pandas中尝试使用gb = df.groupby(['Name','Value2']) - dermen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接