我有以下数据框
prueba =
M1 M2 M3 M4
0 1 1 1 NaN
1 2 3 3 NaN
2 3 2 2 1
3 4 NaN 1 NaN
4 1 NaN NaN NaN
5 1 3 2 2
6 3 3 NaN 1
7 2 2 3 NaN
8 1 3 NaN 1
9 6 4 5 5
我需要为每一行执行两项任务:
如果一列是空的(NaN)并且后面的有一个值,则该值保留在第一个空列中,而NaN保留在其他列中...即,将值向左移动
如果一行中两个值相等,则只在出现的第一列留下:例如,如果M1和M2相等,则M1中只保留该值,M2变为NaN,如果该值在几个M中重复出现它应该只留在第一个和其他 NaN 上。
我尝试了以下选项:
对于第一个问题,尝试成对比较。例如对于 M2 和 M3:
for row in prueba.itertuples():
prueba['M2']= prueba.where((prueba['M2'].isnull() & prueba['M3'].notnull()), prueba['M3'])
但它会产生错误。
对于第二个问题(这部分有效)
prueba.loc[prueba['M1']== prueba['M2'] , 'M2'] = 'NaN'
prueba.loc[prueba['M1']== prueba['M3'] , 'M3'] = 'NaN'
prueba.loc[prueba['M1']== prueba['M4'] , 'M4'] = 'NaN'
prueba.loc[prueba['M2']== prueba['M3'] , 'M3'] = 'NaN'
prueba.loc[prueba['M2']== prueba['M4'] , 'M4'] = 'NaN'
prueba.loc[prueba['M3']== prueba['M4'] , 'M4'] = 'NaN'
我是编程新手,如果您能帮助我解决提到的两个问题,我将不胜感激。寻找解决方案所花费的时间很重要,因为有大量数据。
处理后的 Dataframe 应该是这样的:
M1 M2 M3 M4
0 1 NaN NaN NaN
1 2 3 NaN NaN
2 3 2 1 NaN
3 4 1 NaN NaN
4 1 NaN NaN NaN
5 1 3 2 NaN
6 3 1 NaN NaN
7 2 3 NaN NaN
8 1 3 NaN NaN
9 6 4 5 NaN
对于第二点,它可以通过
pandas.Series.drop_duplicates
传递参数keep="first"
以仅保留第一次出现以一般方式使用。带有的布尔掩码pandas.Series.duplicated
也可以。对于第一点,我想不出矢量化的形式。可以通过使用
pandas.DataFrame.apply
rows(axis=1
) 并为每一行调用一个 Python 函数来执行此操作,该函数使用该方法pandas.Series.dropna
构造新行。通过上述我们获得了一个 DataFrame ,它允许我们重现您的示例:
现在让我们应用之前解释的想法:
有了这个,我们得到了非常接近的东西:
我们只需要添加缺失的列(包含所有 NaN 值的列)并重命名其余列:
结果:
我不知道我是否理解正确,但我认为它是关于:
虽然这个说法和你说的不一样,但我觉得最后结果是一样的,这样表达更清楚。
事实上,这提出了另一种不使用 Pandas 来计算结果的方法,而是提取数据帧底层的二维数组。在这个数组中,问题是逐行遍历它,并为每个数组构建一个包含其元素的集合(这些集合会自动消除重复项)。在这个转换之后,会有只有两个元素的行,其他的有四个,等等。
最后,可以使用所有这些集合构建一个新的数据框。由于 Pandas 将其转换为数据框将使所有行的长度相同,因此它将用 NaN 填充缺失的元素。
前一个想法的问题是集合没有内部顺序,因此例如第一行会产生一个包含元素的集合
1, NaN
,或者可能包含元素NaN, 1
。也就是说,元素添加到集合中的顺序不会被保留,这对我们来说并不方便,因为我们希望在它们再次扩展为行时尊重该顺序。对此的解决方案包括以下技巧。我们使用 a 代替集合,
OrderdeDict()
它是一个字典,保留了将键添加到其中的顺序。我们使用每一行的元素来创建该字典的键(值无关紧要,我将使用True
)。重复的密钥存储在与以前相同的密钥中。如果最后我们获取结果字典的键.keys()
(也就是说,直截了当,这是我的想法:
结果:
更新
@Carolina 在评论中向我指出第 3 行不符合规范。事实上,所有的 NaN 并没有放在一起在它的右边。
错误来自这样一个事实,即将每个元素放入有序字典的循环也将
NaN
. 我们真的只想保留数字的原始顺序,而不是NaN
. 因此,不将它们放入字典就足够NaN
了,即:问题是现在列表
r
将包含没有任何结果的行NaN
,因此当从它们创建 DataFrame 时,最终的列数可能会少于我们最初拥有的列数,例如(并且是这种情况)右侧是只有 NaN 的列。为了解决第二个问题,我将使用以下技巧。首先,我使用我拥有的数据创建一个数据框
r
。该数据框通常有 N 列,其中 N<=4。然后我通过从原始数据框中复制名称来命名这些列,但只复制前 N 个名称。最后,我使用reindex()
in columns 将列数扩展到数据框最初具有的列数。这将用 NaN 填充您需要添加的任何额外列。即:现在是的: