如何转换大数据框
How to transform a large data frame
我想转换以下数据框,但似乎无法获得执行此操作的正确函数。每当我使用 'melt' 时,系统都会提示我转换为数组,但数组似乎不接受列名。
无论如何,任何帮助解决这个问题的方法:
一个
B
C1
C1.A
C2
C2.A
PC
11001
核心
旧
SE
新建
进入这个:
一个
B
C
C.A
PC
11001
核心
旧
PC
11001
SE
新建
将不胜感激。
第一个和第二个 df 的代码。
df1 = {'A': ['PC'], 'B': [11001],'C1':['Core'],'C1.A':['Old'],'C2':['SE'],'C2.A':['New']}
df1 = pd.DataFrame(data=df1)`
df2 = {'A': ['PC','PC'], 'B': [11001,11001],'C':['Core','SE'],'C.A':['Old','New']}
df2 = pd.DataFrame(data=df2)
稍微重新格式化一下列,就可以使用 pd.wide_to_long
:
df.columns = df.columns.str.replace(r'C(\d+).A', r'C.A', regex=True)
df = (
pd.wide_to_long(df, stubnames=['C', 'C.A'], i=['A', 'B'], j='drop')
.droplevel(axis=0, level='drop')
.reset_index()
)
df
:
A B C C.A
0 PC 11001 Core Old
1 PC 11001 SE New
将 df
中的列更改为:
A B C1 C1.A C2 C2.A
0 PC 11001 Core Old SE New
到
df.columns = df.columns.str.replace(r'C(\d+).A', r'C.A', regex=True)
A B C1 C.A1 C2 C.A2
0 PC 11001 Core Old SE New
然后 wide_to_long
存根名称 C
和 C.A
不影响df
的替代方案:
new_df = (
pd.wide_to_long(
df.rename(columns=dict(
zip(df.columns,
df.columns.str.replace(r'C(\d+).A', r'C.A', regex=True)))
),
stubnames=['C', 'C.A'],
i=['A', 'B'],
j='drop')
.droplevel(axis=0, level='drop')
.reset_index()
)
new_df
:
A B C C.A
0 PC 11001 Core Old
1 PC 11001 SE New
df
:
A B C1 C1.A C2 C2.A
0 PC 11001 Core Old SE New
使用 replace
将列转换为 MultiIndex
,然后使用 split
,然后 stack
重塑框架以将其转换为所需格式
df = df1.set_index(['A', 'B'])
df.columns = df.columns\
.str.replace(r'^(\D+)(\d+)(.*)', r'_')\
.str.split('_', expand=True)
df = df.stack().droplevel(2).reset_index()
A B C C.A
0 PC 11001 Core Old
1 PC 11001 SE New
感谢您输入代码。我会接受的。 :)
以下是一些想法:
- 您已经对单行结果进行了硬编码,这是一个好的开始。
- 我们可以将该代码与自定义函数一起使用,然后使用
groupy.apply
从单行数据生成新的两行结果(数据帧)。 groupby.apply
将处理与您的新数据框的组合。
- 之后,如果需要重新索引。
首先,我们为 groupby 定制一个应用函数:
def make_new_df_from_row(df):
row = df.iloc[0, :] # df is each df split by groupby
dd = pd.DataFrame({ #configure your hardcode
'A': row.A, 'B': row.B,
'C':[row.C1, row.C2],
'C.A':[row['C1.A'], row['C2.A']] #column name with '.' cannot use row.C1.A
})
return dd
然后,使用df2 = df1.groupby(lambda x:x, group_keys=False).apply(make_new_df_from_row)
得到你想要的结果。
有来自colab的截图:
一些笔记:
- groupby 接受一个使用索引作为输入并从函数输出中拆分数据帧的函数,这里只使用一个 lambda 函数,return 索引本身,按每一行(单行数据帧)拆分数据帧.
group_keys=False
表示不要 return 键(分组索引)
groupby.apply
接受一个输入是每个 groupby 数据帧的函数,你可以 return 一个 pd.Series 或 pd.Dataframe 取决于你的需要。在这里,我们 return 来自您的代码输入的两行数据框(有一些变量更改)
除了已经提供的其他解决方案之外,pivot_longer from pyjanitor 是另一种选择 -> 您的列具有我们可以利用的模式(一些以数字结尾,另一些以 A 结尾):
# pip install pyjanitor
import janitor
import pandas as pd
df.pivot_longer(index=['A', 'B'],
names_to = ['C', 'C.A'],
names_pattern = ['.+\d$', '.+A$'])
A B C C.A
0 PC 11001 Core Old
1 PC 11001 SE New
names_to
中的列成为新的列名,并映射到与names_pattern
中的正则表达式相匹配的旧列。
我想转换以下数据框,但似乎无法获得执行此操作的正确函数。每当我使用 'melt' 时,系统都会提示我转换为数组,但数组似乎不接受列名。
无论如何,任何帮助解决这个问题的方法:
一个 | B | C1 | C1.A | C2 | C2.A |
---|---|---|---|---|---|
PC | 11001 | 核心 | 旧 | SE | 新建 |
进入这个:
一个 | B | C | C.A |
---|---|---|---|
PC | 11001 | 核心 | 旧 |
PC | 11001 | SE | 新建 |
将不胜感激。
第一个和第二个 df 的代码。
df1 = {'A': ['PC'], 'B': [11001],'C1':['Core'],'C1.A':['Old'],'C2':['SE'],'C2.A':['New']}
df1 = pd.DataFrame(data=df1)`
df2 = {'A': ['PC','PC'], 'B': [11001,11001],'C':['Core','SE'],'C.A':['Old','New']}
df2 = pd.DataFrame(data=df2)
稍微重新格式化一下列,就可以使用 pd.wide_to_long
:
df.columns = df.columns.str.replace(r'C(\d+).A', r'C.A', regex=True)
df = (
pd.wide_to_long(df, stubnames=['C', 'C.A'], i=['A', 'B'], j='drop')
.droplevel(axis=0, level='drop')
.reset_index()
)
df
:
A B C C.A
0 PC 11001 Core Old
1 PC 11001 SE New
将 df
中的列更改为:
A B C1 C1.A C2 C2.A
0 PC 11001 Core Old SE New
到
df.columns = df.columns.str.replace(r'C(\d+).A', r'C.A', regex=True)
A B C1 C.A1 C2 C.A2
0 PC 11001 Core Old SE New
然后 wide_to_long
存根名称 C
和 C.A
不影响df
的替代方案:
new_df = (
pd.wide_to_long(
df.rename(columns=dict(
zip(df.columns,
df.columns.str.replace(r'C(\d+).A', r'C.A', regex=True)))
),
stubnames=['C', 'C.A'],
i=['A', 'B'],
j='drop')
.droplevel(axis=0, level='drop')
.reset_index()
)
new_df
:
A B C C.A
0 PC 11001 Core Old
1 PC 11001 SE New
df
:
A B C1 C1.A C2 C2.A
0 PC 11001 Core Old SE New
使用 replace
将列转换为 MultiIndex
,然后使用 split
,然后 stack
重塑框架以将其转换为所需格式
df = df1.set_index(['A', 'B'])
df.columns = df.columns\
.str.replace(r'^(\D+)(\d+)(.*)', r'_')\
.str.split('_', expand=True)
df = df.stack().droplevel(2).reset_index()
A B C C.A
0 PC 11001 Core Old
1 PC 11001 SE New
感谢您输入代码。我会接受的。 :)
以下是一些想法:
- 您已经对单行结果进行了硬编码,这是一个好的开始。
- 我们可以将该代码与自定义函数一起使用,然后使用
groupy.apply
从单行数据生成新的两行结果(数据帧)。groupby.apply
将处理与您的新数据框的组合。 - 之后,如果需要重新索引。
首先,我们为 groupby 定制一个应用函数:
def make_new_df_from_row(df):
row = df.iloc[0, :] # df is each df split by groupby
dd = pd.DataFrame({ #configure your hardcode
'A': row.A, 'B': row.B,
'C':[row.C1, row.C2],
'C.A':[row['C1.A'], row['C2.A']] #column name with '.' cannot use row.C1.A
})
return dd
然后,使用df2 = df1.groupby(lambda x:x, group_keys=False).apply(make_new_df_from_row)
得到你想要的结果。
有来自colab的截图:
一些笔记:
- groupby 接受一个使用索引作为输入并从函数输出中拆分数据帧的函数,这里只使用一个 lambda 函数,return 索引本身,按每一行(单行数据帧)拆分数据帧.
group_keys=False
表示不要 return 键(分组索引)groupby.apply
接受一个输入是每个 groupby 数据帧的函数,你可以 return 一个 pd.Series 或 pd.Dataframe 取决于你的需要。在这里,我们 return 来自您的代码输入的两行数据框(有一些变量更改)
除了已经提供的其他解决方案之外,pivot_longer from pyjanitor 是另一种选择 -> 您的列具有我们可以利用的模式(一些以数字结尾,另一些以 A 结尾):
# pip install pyjanitor
import janitor
import pandas as pd
df.pivot_longer(index=['A', 'B'],
names_to = ['C', 'C.A'],
names_pattern = ['.+\d$', '.+A$'])
A B C C.A
0 PC 11001 Core Old
1 PC 11001 SE New
names_to
中的列成为新的列名,并映射到与names_pattern
中的正则表达式相匹配的旧列。