【问题标题】:Creating Dataframe from inconsistently named columns从名称不一致的列创建数据框
【发布时间】:2017-05-26 23:21:44
【问题描述】:

我有一个 pandas.DataFrame,由于文件 (.csv) 的命名不一致,它有多余的列名。这导致列的大部分是 NaN 值

Bike #  Bikenumber  Bike#   SubscriberType  SubscriptionType
 NaN       NaN     W20848      NaN             Subscriber
 NaN       NaN     W20231      NaN             Subscriber
 NaN       NaN     W00785      NaN             Subscriber
 NaN       NaN     W00126      NaN             Subscriber
 NaN       NaN     W20929      NaN             Casual

有没有办法创建一个新列并从具有值的多个列中填充它?如果不止一列不是NaN,我可以选择从哪一列提取值吗?

 Bike#   Bikenumber   Bike #   Selected_Num
number1   number2      NaN       number2

我可以在尝试填充单列时得到这个

sample['Bike_Num'] = sample['Bike #'].fillna(sample['Bike#'])
print(sample)

    Bike #  Bikenumber  Bike#   SubscriberType  SubscriptionType   Bike_Num
     NaN       NaN     W20848      NaN             Subscriber       W20848
     NaN       NaN     W20231      NaN             Subscriber       W20231
     NaN       NaN     W00785      NaN             Subscriber       W00785
     NaN       NaN     W00126      NaN             Subscriber       W00126
     NaN       NaN     W20929      NaN             Casual           W20929

这失败了

sample['Bike_Num'] = sample['Bike #'].fillna(sample['Bike#'], sample['Bikenumber'])

ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

【问题讨论】:

  • 在从 csv 读取数据时清理数据不是更好吗?如何从 csv 文件中读取数据?
  • @StephenRauch:我从目录中读取了大约 20 个 csv 文件,其中包含 for 循环并将它们与 total_df = pd.concat(dfs, ignore_index = True) 连接起来。
  • 您正在使用pandas.read_csv?我也理解你基本上有一些列名的同义词列表是正确的吗?
  • @StephenRauch 没错,我使用的是pandas.read_csv,是的,列名是同义词,但它们的命名略有不同。 IE。 Bike# = Bike # = Bikenumber

标签: python python-3.x csv pandas dataframe


【解决方案1】:

我建议您在阅读 CSV 文件时解决此问题,而不是稍后尝试解开它们。一种方法是在将 CSV 文件传递​​给 pandas 之前使用小型解析器。

此解析器获取csv 的打开文件句柄,以及将所需列名映射到各种可能同义词的字典。

代码:

def read_my_csv(file_handle, column_map):
    # reverse the column mapping dict to use for synonym lookup
    synoms = dict(sum([
        [(syn, k) for syn in v] for k, v in column_map.items()], []))

    # build csv reader
    reader = csv.reader(file_handle)

    # get the header, and map columns to desired names
    header = next(reader)
    header = [synoms.get(c, c) for c in header]

    # yield the header
    yield header

    # yield the remaining rows
    for row in reader:
        yield row

测试代码:

import pandas as pd
import csv

column_map = {
    'Bike_Num': ('Bike #', 'Bikenumber', 'Bike#'),
    'Sub_Num': ('SubscriberType', 'SubscriptionType'),
}

with open("sample.csv", 'rU') as f:
    generator = read_my_csv(f, column_map)
    columns = next(generator)
    df = pd.DataFrame(generator, columns=columns)

print(df)

Sample.csv:

Bike #,SubscriptionType
W20848,Subscriber
W20231,Subscriber
W00785,Subscriber
W00126,Subscriber
W20929,Casual

结果:

  Bike_Num     Sub_Num
0   W20848  Subscriber
1   W20231  Subscriber
2   W00785  Subscriber
3   W00126  Subscriber
4   W20929      Casual

解决方案 #2

一个更简洁但不那么有趣的解决方案是在执行连接之前重命名列:

代码:

def fix_column_names(df, column_map):
    # reverse the column mapping dict to use for synonym lookup
    synoms = dict(sum([
        [(syn, k) for syn in v] for k, v in column_map.items()], []))

    # rename columns
    df.columns = [synoms.get(c, c) for c in df.columns]

测试代码:

import pandas as pd
import csv

column_map = {
    'Bike_Num': ('Bike #', 'Bikenumber', 'Bike#'),
    'Sub_Num': ('SubscriberType', 'SubscriptionType'),
}

df = pd.read_csv('sample.csv', header=0)
fix_column_names(df, column_map)
print(df)

【讨论】:

  • 这太好了,非常感谢!我对 python 还很陌生,这是我没有考虑过的一种方法。爱它! :)
猜你喜欢
  • 2017-12-10
  • 1970-01-01
  • 2019-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-13
  • 1970-01-01
相关资源
最近更新 更多