【问题标题】:Allow duplicate columns in Pandas允许 Pandas 中的重复列
【发布时间】:2022-05-08 10:07:37
【问题描述】:

我正在将一个大型 CSV(包含股票财务数据)文件拆分为更小的块。 CSV 文件的格式不同。类似于 Excel 数据透视表的东西。第一列的前几行包含一些标题。

公司名称、ID 等在以下列中重复。因为一家公司有多个属性,而不是一家公司只有一栏。

在前几行之后,列开始类似于典型的数据框,其中标题位于列中而不是行中。

无论如何,我要做的是让 Pandas 允许重复的列标题,而不是让它在标题之后添加“.1”、“.2”、“.3”等。我知道 Pandas 本身不允许这样做,有解决方法吗?我尝试在 read_csv 上设置 header = None,但它会引发我认为有意义的标记化错误。我只是想不出一个简单的方法。

import pandas as pd

csv_path = "C:\\Users\\ThirdHandBD\\Desktop\\Data Splitting\\pd-split\\chunk4.csv"

#df = pd.read_csv(csv_path, header=1, dtype='unicode', sep=';', low_memory=False, error_bad_lines=False)
df = pd.read_csv(csv_path, header = 1, dtype='unicode', sep=';', index_col=False)
print("I read in a dataframe with {} columns and {} rows.".format(
len(df.columns), len(df)
))

filename = 1

#column increment
x = 30 * 59

for column in df:
    loc = df.columns.get_loc(column)
    if loc == (x * filename) + 1:
        y = filename - 1
        a = (x * y) + 1
        b = (x * filename) + 1
        date_df = df.iloc[:, :1]
        out_df = df.iloc[:, a:b]
        final_df = pd.concat([date_df, out_df], axis=1, join='inner')
        out_path = "C:\\Users\\ThirdHandBD\\Desktop\\Data Splitting\\pd-split\\chunk4-part" + str(filename) + ".csv"
        final_df.to_csv(out_path, index=False)
        #out_df.to_csv(out_path)
        filename += 1

# This should be the same as df, but with only the first column.
# Check it with similar code to above.

编辑:

来自https://github.com/pandas-dev/pandas/issues/19383,我补充说:

        final_df.columns = final_df.iloc[0]
        final_df = final_df.reindex(final_df.index.drop(0)).reset_index(drop=True)

所以,完整的代码:

import pandas as pd

csv_path = "C:\\Users\\ThirdHandBD\\Desktop\\Data Splitting\\pd-split\\chunk4.csv"

#df = pd.read_csv(csv_path, header=1, dtype='unicode', sep=';', low_memory=False, error_bad_lines=False)
df = pd.read_csv(csv_path, header = 1, dtype='unicode', sep=';', index_col=False)
print("I read in a dataframe with {} columns and {} rows.".format(
len(df.columns), len(df)
))

filename = 1

#column increment
x = 30 * 59

for column in df:
    loc = df.columns.get_loc(column)
    if loc == (x * filename) + 1:
        y = filename - 1
        a = (x * y) + 1
        b = (x * filename) + 1
        date_df = df.iloc[:, :1]
        out_df = df.iloc[:, a:b]
        final_df = pd.concat([date_df, out_df], axis=1, join='inner')
        out_path = "C:\\Users\\ThirdHandBD\\Desktop\\Data Splitting\\pd-split\\chunk4-part" + str(filename) + ".csv"
        final_df.columns = final_df.iloc[0]
        final_df = final_df.reindex(final_df.index.drop(0)).reset_index(drop=True)
        final_df.to_csv(out_path, index=False)
        #out_df.to_csv(out_path)
        filename += 1

# This should be the same as df, but with only the first column.
# Check it with similar code to above.

现在,整个第一行都消失了。但是,预期的输出是将标题行替换为重置索引,没有“.1”、“.2”等。

截图:

SimFin ID 行不再存在。

【问题讨论】:

标签: python pandas


【解决方案1】:

我就是这样做的:

    final_df.columns = final_df.columns.str.split('.').str[0]

参考: https://pandas.pydata.org/pandas-docs/stable/text.html

【讨论】:

  • 这假定没有其他列有真正的“。”字符。
  • 方法异常!
  • 如果列名有一个真正的“。”这将失败。里面的人物。
【解决方案2】:

以下解决方案将确保数据框中带有符号句点 ('.') 的其他列名不会被修改

import pandas as pd
from csv import DictReader

csv_file_loc = "file.csv"

# Read csv  
df = pd.read_csv(csv_file_loc)

# Get column names from csv file using DictReader  
col_names = DictReader(open(csv_file_loc, 'r')).fieldnames

# Rename columns  
df.columns = col_names 

【讨论】:

    【解决方案3】:

    我知道我在这个问题上已经很晚了,但我会留下我想出的解决方案,以防其他人像我一样徘徊。

    首先,链接的问题有一个非常好的动态解决方案,即使对于高列数来说似乎也能很好地工作。在我提出解决方案后,我遇到了,哈哈。看看here。该线程上的另一个答案利用csv library 来读取和使用其中的列名,因为它似乎不像 Pandas 那样修改重复项。这应该可以正常工作,但我只是想避免使用任何额外的库,尤其是考虑到我最初使用的是 csv,然后升级到 Pandas 以获得更好的功能。

    现在这是我的解决方案。我确信它可以做得更好,但据我所知,这可以满足我的需要并且非常动态。它基本上遍历列,检查它是否可以根据最右边的“。”拆分字符串。 (即rpartition),然后从那里进行更多检查。

    它检查:

    1. 这个字符串在 colMap 中吗? colMap 跟踪所有列名,无论是否重复。如果返回为真,则意味着它与之前的另一列重复。

    2. 是最右边的“.”之后的字符串一个号码?所有的列都是字符串,所以这只是确保无论它是什么都可以转换为一个数字,以防止抓取其他符合先前条件但实际上不是 Pandas 的随机列。例如。 “DupeCol”和“DupeCol.Stuff”不会被拾取,但“DupeCol”和“DupeCol.1”会。

    3. 最右边的“.”后面的数字是不是。与 colMap 中的当前重复数相匹配?由于 colMap 包含所有列的名称,无论是否重复,这将确保我们不会抓取与 Pandas 使用的“.number”约定重叠的用户命名列。例如。如果用户将两列命名为“DupeCol”和“DupeCol.6”,则不会被拾取除非在“DupeCol.6”之前有6个“DupeCol”,这表明它几乎必须是这样命名的 Pandas,而不是用户。 这部分肯定有点矫枉过正,但我​​觉得要特别彻底。

    colMap = []
    
    for col in df.columns:
        if col.rpartition('.')[0]:
            colName = col.rpartition('.')[0]
            inMap = col.rpartition('.')[0] in colMap
            lastIsNum = col.rpartition('.')[-1].isdigit()
            dupeCount = colMap.count(colName)
    
            if inMap and lastIsNum and (int(col.rpartition('.')[-1]) == dupeCount):
                colMap.append(colName)
                continue
        colMap.append(col)
            
    df.columns = colMap

    希望这对某人有所帮助!如果您认为它可以使用任何改进,请随时发表评论。我并不完全喜欢在我的代码中使用“继续”,但我不确定这是否是因为它实际上是不好的做法,或者只是我阅读随机的人抱怨它太多。我认为这里的代码不会太难读,也不会重复“else”语句;但让我知道是否有办法改进它或其他任何东西。我一直在学习!

    【讨论】:

      猜你喜欢
      • 2018-10-25
      • 2015-01-25
      • 2019-01-13
      • 1970-01-01
      • 1970-01-01
      • 2021-10-25
      • 1970-01-01
      • 2013-06-07
      相关资源
      最近更新 更多