在列和行中具有不同长度列表的数据框中拆分列表
Split lists in a dataframe with different length lists in columns and rows
所以我的问题与此类似。我的不同,因为我在同一行和同一列上有不同长度的列表。
我尝试过的许多解决方案都会产生一个非常长的数据帧,其中包含多次重复。我的要求是逐行的,这意味着如果一行有一个列表,它会被分成所需数量的行,但不会导致多次重复。请看下面的例子。
输入示例
import pandas as pd
df = pd.DataFrame(
{'C1': [["A","B"], ["C"], ["D","E"], ["F"]],
'C2': [[1], [2], [3], [4]],
'C3': ['s1', 's2', 's3', 's4'],
'C4': [123, 321, [777,111], 145]})
df
期望的输出示例
我一直在尝试 explode()
、reset_index()
、drop()
等等,但还没有得到任何东西来提供正确的输出。
我试过的一件事是这个
df = df.explode("C1").reset_index().drop("index",1).explode("C4").reset_index().drop("index",1)
但是输出错误
df=df.explode('C4').assign(C1=df['C1'].str.join(',').str.split(',')).explode('C1')#Explode to expand dataframe
m=df.duplicated(subset='C1', keep=False)#loc select the duplicated
df.loc[m,'C4']=df.loc[m,'C4'].shift(1)#Introduce Nan
df.dropna().drop_duplicates(subset='C1', keep='last')#clean dataframe
输出
C1 C2 C3 C4
0 A [1] s1 123
0 B [1] s1 123
1 C [2] s2 321
2 D [3] s3 777
2 E [3] s3 111
3 F [4] s4 145
似乎需要将展开的列和未展开的列分开。由于我们不能像通常那样将它们隐藏在索引中(给定 C2
)包含列表(不可散列)我们必须分离 DataFrame 然后重新加入。
# Convert to single series to explode
cols = ['C1', 'C4']
new_df = df[cols].stack().explode().to_frame()
# Enumerate groups then unstack
new_df = new_df.set_index(
new_df.groupby(level=[0, 1]).cumcount(),
append=True
).unstack(1).groupby(level=0).ffill()
# Join Back Unaffected columns
new_df = new_df.droplevel(0, axis=1).droplevel(1, axis=0).join(
df[df.columns.symmetric_difference(cols)]
)
# Re order columns and reset index
new_df = new_df.reindex(df.columns, axis=1).reset_index(drop=True)
new_df
:
C1 C2 C3 C4
0 A [1] s1 123
1 B [1] s1 123
2 C [2] s2 321
3 D [3] s3 777
4 E [3] s3 111
5 F [4] s4 145
我们stack
to get all values into a single series then explode
together and convert back to_frame
cols = ['C1', 'C4']
new_df = df[cols].stack().explode().to_frame()
new_df
0
0 C1 A
C1 B
C4 123
1 C1 C
C4 321
2 C1 D
C1 E
C4 777
C4 111
3 C1 F
C4 145
我们可以通过 groupby cumcount
set_index
and unstacking
:
枚举组来创建新索引
new_df = new_df.set_index(
new_df.groupby(level=[0, 1]).cumcount(),
append=True
).unstack(1)
0
C1 C4
0 0 A 123
1 B NaN
1 0 C 321
2 0 D 777
1 E 111
3 0 F 145
然后我们可以 groupby ffill
在索引组中:
new_df = new_df.groupby(level=0).ffill()
new_df
:
0
C1 C4
0 0 A 123
1 B 123
1 0 C 321
2 0 D 777
1 E 111
3 0 F 145
然后我们可以join
back the unaffected columns to the DataFrame and reindex
to reorder them the way the initially appeared also droplevel
to remove unneeded index levels, lastly reset_index
:
# Join Back Unaffected columns
new_df = new_df.droplevel(0, axis=1).droplevel(1, axis=0).join(
df[df.columns.symmetric_difference(cols)]
)
# Re order columns and reset index
new_df = new_df.reindex(df.columns, axis=1).reset_index(drop=True)
new_df
:
C1 C2 C3 C4
0 A [1] s1 123
1 B [1] s1 123
2 C [2] s2 321
3 D [3] s3 777
4 E [3] s3 111
5 F [4] s4 145
所以我的问题与此类似
我尝试过的许多解决方案都会产生一个非常长的数据帧,其中包含多次重复。我的要求是逐行的,这意味着如果一行有一个列表,它会被分成所需数量的行,但不会导致多次重复。请看下面的例子。
输入示例
import pandas as pd
df = pd.DataFrame(
{'C1': [["A","B"], ["C"], ["D","E"], ["F"]],
'C2': [[1], [2], [3], [4]],
'C3': ['s1', 's2', 's3', 's4'],
'C4': [123, 321, [777,111], 145]})
df
期望的输出示例
我一直在尝试 explode()
、reset_index()
、drop()
等等,但还没有得到任何东西来提供正确的输出。
我试过的一件事是这个
df = df.explode("C1").reset_index().drop("index",1).explode("C4").reset_index().drop("index",1)
但是输出错误
df=df.explode('C4').assign(C1=df['C1'].str.join(',').str.split(',')).explode('C1')#Explode to expand dataframe
m=df.duplicated(subset='C1', keep=False)#loc select the duplicated
df.loc[m,'C4']=df.loc[m,'C4'].shift(1)#Introduce Nan
df.dropna().drop_duplicates(subset='C1', keep='last')#clean dataframe
输出
C1 C2 C3 C4
0 A [1] s1 123
0 B [1] s1 123
1 C [2] s2 321
2 D [3] s3 777
2 E [3] s3 111
3 F [4] s4 145
似乎需要将展开的列和未展开的列分开。由于我们不能像通常那样将它们隐藏在索引中(给定 C2
)包含列表(不可散列)我们必须分离 DataFrame 然后重新加入。
# Convert to single series to explode
cols = ['C1', 'C4']
new_df = df[cols].stack().explode().to_frame()
# Enumerate groups then unstack
new_df = new_df.set_index(
new_df.groupby(level=[0, 1]).cumcount(),
append=True
).unstack(1).groupby(level=0).ffill()
# Join Back Unaffected columns
new_df = new_df.droplevel(0, axis=1).droplevel(1, axis=0).join(
df[df.columns.symmetric_difference(cols)]
)
# Re order columns and reset index
new_df = new_df.reindex(df.columns, axis=1).reset_index(drop=True)
new_df
:
C1 C2 C3 C4
0 A [1] s1 123
1 B [1] s1 123
2 C [2] s2 321
3 D [3] s3 777
4 E [3] s3 111
5 F [4] s4 145
我们stack
to get all values into a single series then explode
together and convert back to_frame
cols = ['C1', 'C4']
new_df = df[cols].stack().explode().to_frame()
new_df
0
0 C1 A
C1 B
C4 123
1 C1 C
C4 321
2 C1 D
C1 E
C4 777
C4 111
3 C1 F
C4 145
我们可以通过 groupby cumcount
set_index
and unstacking
:
new_df = new_df.set_index(
new_df.groupby(level=[0, 1]).cumcount(),
append=True
).unstack(1)
0
C1 C4
0 0 A 123
1 B NaN
1 0 C 321
2 0 D 777
1 E 111
3 0 F 145
然后我们可以 groupby ffill
在索引组中:
new_df = new_df.groupby(level=0).ffill()
new_df
:
0
C1 C4
0 0 A 123
1 B 123
1 0 C 321
2 0 D 777
1 E 111
3 0 F 145
然后我们可以join
back the unaffected columns to the DataFrame and reindex
to reorder them the way the initially appeared also droplevel
to remove unneeded index levels, lastly reset_index
:
# Join Back Unaffected columns
new_df = new_df.droplevel(0, axis=1).droplevel(1, axis=0).join(
df[df.columns.symmetric_difference(cols)]
)
# Re order columns and reset index
new_df = new_df.reindex(df.columns, axis=1).reset_index(drop=True)
new_df
:
C1 C2 C3 C4
0 A [1] s1 123
1 B [1] s1 123
2 C [2] s2 321
3 D [3] s3 777
4 E [3] s3 111
5 F [4] s4 145