从旧 DataFrame 中的行切片追加或创建 DataFrame

Appending or creating dataframe from row slices from old dataframe

提问人:MapPeddler 提问时间:12/22/2017 最后编辑:MapPeddler 更新时间:1/4/2018 访问量:1731

问:

我在数据框中有一个表,其中年份列范围为 2001-2018,单元格值范围为 1-9。我正在尝试遍历我的原始数据帧,对于每条记录/行,在最近出现的“9”之后附加该行的所有值。有一些条件要求,但我遇到的问题的症结在于将切片行放入可以导出的新数据帧中。它目前在 80,000 条记录上运行,但只完成了 8,000 条记录,因此效率相当低下。我也非常有信心它不会保留整行,而是将每行的最后一个值设置为新数据帧中的所有单元格值。

这是我的数据帧作为字典的输出:

{2001L: {0: nan, 1: nan, 2: nan, 3: nan, 4: nan},
 2002L: {0: 8.0, 1: nan, 2: nan, 3: nan, 4: nan},
 2003L: {0: nan, 1: 8.0, 2: 7.0, 3: 8.0, 4: 8.0},
 2004L: {0: nan, 1: nan, 2: 8.0, 3: 6.0, 4: 8.0},
 2005L: {0: 8.0, 1: 8.0, 2: nan, 3: nan, 4: nan},
 2006L: {0: nan, 1: 8.0, 2: nan, 3: 8.0, 4: 9.0},
 2007L: {0: nan, 1: 7.0, 2: nan, 3: nan, 4: nan},
 2008L: {0: 8.0, 1: 8.0, 2: nan, 3: 8.5, 4: 8.0},
 2009L: {0: nan, 1: 8.0, 2: nan, 3: 8.0, 4: 8.0},
 2010L: {0: nan, 1: 8.0, 2: 8.0, 3: 8.0, 4: 8.0},
 2011L: {0: nan, 1: 8.0, 2: nan, 3: 8.0, 4: 8.0},
 2012L: {0: nan, 1: 8.0, 2: nan, 3: 8.0, 4: 8.0},
 2013L: {0: nan, 1: 7.0, 2: nan, 3: 8.0, 4: 8.0},
 2014L: {0: nan, 1: 7.0, 2: nan, 3: 8.0, 4: 8.0},
 2015L: {0: nan, 1: 8.0, 2: nan, 3: nan, 4: nan},
 2016L: {0: 8.0, 1: 9.0, 2: nan, 3: 7.0, 4: 8.0},
 2017L: {0: nan, 1: 9.0, 2: nan, 3: 7.0, 4: 8.0},
 2018L: {0: nan, 1: nan, 2: nan, 3: 7.0, 4: 9.0},
 'SegmentID': {0: 15, 1: 16, 2: 17, 3: 18, 4: 19},
 'index': {0: 0, 1: 1, 2: 2, 3: 3, 4: 4}}

这是我尝试作为字典接收的输出。

{'Year0': {0: 9, 1: 9, 2: 9},
'Year1': {0: 9.0, 1: nan, 2: 9.0},
'Year2': {0:None, 1: None, 2: None},
'index': {0: 5, 1: 7, 2: 8}}

这是我试图解决这个问题的代码。

for row in df_ratings_pivot.itertuples():
    for i in range(len(df_ratings_pivot.columns)):
        if row[i] == 9 and row[i-1] <=7 and row[i-2] <= 7:
            for j in range(0,len(df_ratings_pivot.columns)-i):
                for k in range(i,len(df_ratings_pivot.columns)):
                    df_new.set_value(row[0],'Year'+str(j),row[k])
                    print row, j, row[k]

谢谢!

编辑嗨,伊恩,这是我用来修改数据帧的代码。它和你的非常相似。我能看到的唯一区别是,我正在重新索引 df 以将 segID 放在字段列表的末尾,因此它不会影响切片

df_ratings_pivot
df2 = df_ratings_pivot.loc[df_ratings_pivot[df_ratings_pivot ==9].dropna(how = 'all').index]
df2 = df2.reset_index()
cols = df2.columns.tolist()
cols.insert(20, cols.pop(cols.index('SegmentID')))
df2 = df2.reindex(columns=cols)
df2
df2 = df2.astype(str)
df3 = df2.loc[:, df2.max().idxmax():]
df3

我刚刚注意到 idxmax 的错别字。所以我修复了它并且代码有效,但我现在只拉动最后一个 segmentID 列,没有别的。我想这是有道理的,因为您的代码最初没有考虑位于 df 末尾的具有如此高值的 segID 字段。有没有办法在不弄乱切片的情况下保留 SegmentID?

编辑 2

好的,所以我做了你的改变,这是我的屏幕截图形式的结果,希望能加快这个过程。第一个屏幕截图是我将 DF 转换为可由您的代码修改的格式。第二部分是代码的结果。

Code that got me the setup DF

enter image description here

从一开始,似乎就有额外的信息被拉进来了。例如,记录 1 应该从 2016 年开始,因为这是第一次出现 9。第一个记录应该只有 2016 年和 2017 年的 2 个值。也许我应该创建一个新的数据帧并附加到其中,而不是从现有数据帧中切片?

我的最终目标数据帧将从某个任意的 Year0 字段名称开始,该字段名称将填充一堆 9。第 0 年之后的所有内容都将使用相应的记录值进行填充。.在最初的 9.因此,对于记录 1、2 和 3,它将是:

{Year0: {0: 9, 1: 9, 2: 9, ...},
 Year1: {0: 9, 1:nan,2:9, ...},
 Year2: {0: nan, 1: 8, 2: nan, ...},}
python-2.7 pandas 数据帧 追加 切片

评论

0赞 rpanai 12/22/2017
请发布您的原始数据帧(可能)和预期输出。df.to_dict()
0赞 MapPeddler 12/22/2017
我应该用 df.to_dict() 的整个输出编辑上面的内容吗?您所说的预期输出是指我希望接收的最终数据帧,其值以所需方式排列?谢谢你的回复,顺便说一句
1赞 Ian Thompson 12/22/2017
@CambrianCatalyst,“你所说的预期输出是指我希望接收的最终数据帧,其值以所需的方式排列?”——是的。
0赞 rpanai 12/22/2017
@CambrianCatalyst如果太大,你可以只取一个重要的样本。df
0赞 MapPeddler 12/22/2017
非常感谢。我已经用我认为正确的信息编辑了我的父消息。如果我在某个地方搞砸了,我很抱歉。再次感谢所有的帮助!

答:

1赞 Ian Thompson 12/26/2017 #1

只是为了在这里得到答案并希望能更多地理解这个问题,这里有一种方法可以使用您的示例数据删除没有 9 的行并删除前 9 之前的所有列。

# make data into pd.DataFrame
df = pd.DataFrame.from_dict(data)

# make all columns strings
df.columns = df.columns.astype(str)

# sort the columns
df.sort_index(axis = 1, inplace = True)

# drop index
df.drop('index', axis = 1, inplace = True)

df

dropped index

# remove 'SegmentID' for now, join later
df1 = df[df.columns.tolist()[:-1]]

# drop rows without a 9
df2 = df1.loc[df1[df1 == 9].dropna(how = 'all').index]

df2

dropped rows

# drop first columns before first occurrence of 9
df3 = df2.loc[:, df2.max().idxmax():]

dropped unneeded columns

# store index
idx = df3.index

# loop through columns to replace values != 9 with NaN preceeding first 9
for col in df3.columns:
#     remove index with 9
    idx = idx.drop(df3[df3[col] == 9].index)
#     fill values != 9 with NaN
    df3.loc[idx, col] = np.NaN
#     break out of loop when index runs out
    if len(idx) == 0:
        break

# join SegmentID back in
df3.join(df.SegmentID)

output

顺便说一句,我正在使用 Python 3.5.2、Pandas 0.20.3,以防您遇到语法错误。我还转换了您的年份列,以便我可以对列进行切片。str

评论

0赞 MapPeddler 1/3/2018
嗨,伊恩,感谢您的回复。对不起,我自己的回复晚了。直到今天,我才能够访问这些数据。我无法让您的切片在我的数据帧上工作。重要的是,我将 segmentID 保留为列,因此我忽略了删除该字段,但我确实重置了索引,因此它不再用作索引。当我将列转换为字符串并应用 .loc 切片时,我只剩下整个数据帧,就像切片之前一样。
0赞 MapPeddler 1/3/2018
在父级中进行了编辑,以包含我最初错过的错别字。